home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 1.toast / pc / sample code / games / moofwars / tim's libraries / tgraphic.cp < prev    next >
Encoding:
Text File  |  2000-06-23  |  78.7 KB  |  2,785 lines

  1. /*
  2.     File:        TGraphic.cp
  3.  
  4.     Contains:    The TGraphic class encapsulates custom blitting of a graphic to an offscreen
  5.                 environment, such as a GWorld or a DrawSprocket buffer.  The current blitters
  6.                 are refined versions of the RLE sprites in "Tips of the Mac Gaming Gurus".
  7.                 The core blitters do not do any work to align data to proper boundaries, so
  8.                 this code currently does not use doubles to move data (this would be
  9.                 horribly slow on the 603/604 chips).
  10.  
  11.                 In addition to the drawing code, this class also encorporates hit testing
  12.                 graphics to each other or a single point, and using just the mask data to do
  13.                 an erase function. It also has some generalized loading and unloading code.
  14.                 
  15.     Notes:        Currently the encoders are only designed for 8-bit images, and assume that
  16.                 the same color table is being used between the TGraphic encoder and whatever
  17.                 the destination GWorld will be.  The blitters don't really care and should
  18.                 work in anything >= 8 bits in depth, although they haven't been tested in
  19.                 anything other than 8 bits.
  20.  
  21.                 Currently, this class is definitely not intended to be subclassed, so
  22.                 all the methods are non-virtual.
  23.                 
  24.     Written by: Timothy Carroll    
  25.  
  26.     Copyright:    Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved.
  27.  
  28.                 You may incorporate this Apple sample source code into your program(s) without
  29.                 restriction. This Apple sample source code has been provided "AS IS" and the
  30.                 responsibility for its operation is yours. You are not permitted to redistribute
  31.                 this Apple sample source code as "Apple sample source code" after having made
  32.                 changes. If you're going to re-distribute the source, we require that you make
  33.                 it clear in the source that the code was descended from Apple sample source
  34.                 code, but that you've made changes.
  35.  
  36.     Change History (most recent first):
  37.                 7/2/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  38.                 
  39.                 11/5/97        Replaced naked c-types with standard types from types.h.
  40.  
  41.                 9/18/97        CreateGraphic and the utility functions that it was based on
  42.                             were cleaned up.  Now, the utility functions are responsible
  43.                             for cleaning up if they have an error.  Fixed a few bugs in
  44.                             the CIcon code as well.
  45.  
  46.                 9/18/97        Updated code to Universal Headers 3.0.  Cleaned up some of the
  47.                             comments.  Revised code to use OSStatus everywhere.
  48.             
  49.                 5/22/97        Writes to resource file now call UpdateResFile.
  50.  
  51.                 5/21/97        The list that keeps the TGraphics was never being initialized.
  52.                             Perhaps the compiler automatically initializes the variables to
  53.                             NULL, otherwise I would have expected it to explode.  We now
  54.                             explictly initialize the list variables.
  55.             
  56.                 5/21/97        No major changes or bugs fixed, but the list management code has
  57.                             been tidied up.
  58.             
  59.                 5/19/97        WriteToPICTResource could fail to restore the ports properly 
  60.                             if QuickDraw returned an error.  This is fixed now.
  61.             
  62.                 4/2/97        RELEASE OF 1.01
  63.  
  64.                 4/2/97        LoadFromGraphicResource called ReleaseResource twice because I
  65.                             duplicated some code to the cleanup section. Onyx's Spotlight
  66.                             spotted it. Buy it!
  67.  
  68.  
  69.                 2/24/97        TGraphic relies on an application to allocate a color table. This
  70.                             handle is now declared inside TGraphic.h
  71.  
  72.                 2/24/97        Assert macros were moved to a separate file, which we explictly
  73.                             include.  MrC can build it now.
  74.  
  75.                 1/23/97        If garbage were fit into the blitter, it is possible that we
  76.                             could draw before destPtr was initialized.  This could never
  77.                             happen with a valid sprite, but the debug build now initializes
  78.                             the pointer to DEADBEEF to force a bus error.  MrC's optimizer
  79.                             spotted this case in the code.
  80.  
  81. */
  82.  
  83.  
  84. #include <Memory.h>
  85. #include <Resources.h>
  86.  
  87. #include <Icons.h>
  88. #include "TGraphic.h"
  89. #include "Scaling.h"
  90.  
  91.  
  92. /*************************************************************************************
  93. Internal Declarations
  94.  
  95. We define a number of constants used by the encoders and decoders.  Each TGraphic
  96. consists of a number of drawing commands, each of which is a 32-bit unsigned int with
  97. an 8-bit operator and a 24-bit value, followed by zero or more bytes of associated data.
  98.  
  99. Currently, each command is aligned to a 4-byte boundary, so a change in format would
  100. be required to use 8-byte floats.
  101. *************************************************************************************/
  102.  
  103. enum
  104. {
  105. // An EndShape token must appear at the end of all TGraphics.  The value is ignored.
  106.     kEndShapeToken    = 0L,
  107.  
  108. // Each line must be preceded by a LineStart token, even lines with no drawing. The
  109. // data field is the offset to the next line, used for clipping and hit testing.
  110.     kLineStartToken = 1L,
  111.  
  112. // This is the only token that currently has additional data.  The value field is the
  113. // number of bytes of pixel data, and the op-code is followed by that data.  The data
  114. // is padded to a 4-byte boundary.
  115.     kDrawPixelsToken = 2L,
  116.  
  117. // This is the "draw" equivalent in the hit mask.  We encode the hit mask separately
  118. // to allow for certain pixels to be drawn but not hit tested.
  119.     kHitTestPixelsToken = 2L,
  120.  
  121. // Skips a range of pixels, without drawing.
  122.     kSkipPixelsToken = 3L,
  123.  
  124. // The actual colors tested against in the hit mask.  Alpha blending could be added,
  125. // but should be a different opcode to allow opaque pixels to be drawn quickly.
  126.     kClearColorIndex = 0,
  127.     kMaskColorIndex = 255
  128. };
  129.  
  130. // This macro could be modified to support almost any alignment necessary.
  131. #define ALIGN_TO_NEXT_LONG(x)  ( ((UInt32) x + 3) & ~3)
  132.  
  133.  
  134. // Standard declarations for our resource type and format.
  135.  
  136. #define kTGraphicResourceType 'Gfic'
  137.  
  138. struct TGraphicResHeader
  139. {
  140.     UInt32 version;
  141.     SInt16 depth;
  142.     UInt16 flags;
  143.     Rect   bounds;
  144.     UInt32 imageSize;
  145.     UInt32 maskSize;
  146. };
  147. typedef TGraphicResHeader **TGraphicResHeaderHandle;
  148.  
  149.  
  150. // Preferred depth for the encoder.
  151. #define kPreferredDepth 8
  152.  
  153.  
  154. /*************************************************************************************
  155. TGraphic Allocation and List Management
  156.  
  157. TGraphic objects are allocated and maintained in a list internally by this class.
  158. Each object is reference counted, to reduce the amount of time spent loading and
  159. preparing TGraphics.  This is particularly important when you are loading sprites
  160. from PICT resources, since processing the sprites can take a long time.
  161.  
  162. For truly high performance apps, you can preload all the TGraphics once, and use
  163. them, so that no time in the game loop actually gets spent preparing the sprites.
  164.  
  165. The list is sorted by the TGraphic's resource ID, and uses standard C array indexing.
  166. The list is searched using a binary search.    
  167. *************************************************************************************/
  168.  
  169. static Handle gTGraphicList = NULL;
  170. static UInt32 gNumberGraphics = 0;
  171.  
  172. static OSStatus InsertGraphicIntoList (TGraphic *theGraphic, UInt32 index);
  173. static OSStatus DeleteGraphicFromList (UInt32 index);
  174. static OSStatus SearchGraphicList (SInt16 resID, Boolean *found, UInt32 *index);
  175.  
  176.  
  177. /*************************************************************************************
  178. InsertGraphicIntoList
  179.  
  180. This routine creates the list if it hasn't been initialized.  Otherwise, it just
  181. inserts the TGraphic into the spot pointed to by the index.  If an error occurs, the
  182. list is left in an indeterminate state.
  183. *************************************************************************************/
  184.  
  185. OSStatus InsertGraphicIntoList (TGraphic *theGraphic, UInt32 index)
  186. {
  187.     OSStatus theErr = noErr;
  188.  
  189. #if qDebugging
  190.     if (theGraphic == NULL)
  191.         SIGNAL_ERROR ("\pError: Attempted to insert a NULL TGraphic in list.")
  192.     if ((index < 0) || (index > gNumberGraphics))
  193.         SIGNAL_ERROR ("\pError: Attempted to insert TGraphic at invalid index.")
  194. #endif
  195.     
  196.     // If we don't have a list, allocate one.
  197.     if (gTGraphicList == NULL)
  198.     {
  199.         gNumberGraphics = 1;
  200.     
  201.         gTGraphicList = NewHandleClear (sizeof (TGraphic *));
  202.         theErr = MemError();
  203.         FAIL_OSERR (theErr, "\pERROR: Couldn't allocate TGraphic list.")
  204.         FAIL_NIL (gTGraphicList, "\pERROR: Couldn't allocate TGraphic list.")
  205.     }
  206.     else
  207.     // if we do have a list, expand it by one node
  208.     {
  209.         gNumberGraphics++;
  210.         
  211.         SetHandleSize(gTGraphicList,gNumberGraphics*sizeof(TGraphic *));
  212.         theErr = MemError();
  213.         FAIL_OSERR (theErr, "\pERROR: Couldn't resize TGraphic list")
  214.         FAIL_NIL (gTGraphicList, "\pERROR: Couldn't resize TGraphic list")
  215.         
  216.         // Make room in the list for a node at the correct index.
  217.         BlockMoveData(    (*(TGraphic ***)gTGraphicList)+index,
  218.                         (*(TGraphic ***)gTGraphicList)+index+1,
  219.                         (gNumberGraphics - index-1) * sizeof(TGraphic *));
  220.     }
  221.     
  222.     // Copy the TGraphic into the list.
  223.     *((*(TGraphic ***) gTGraphicList)+index) = theGraphic;
  224.  
  225.     // We succeeded, cleanup and exit.
  226.     goto cleanup;
  227.     
  228. error:
  229.     if (theErr == noErr)
  230.         theErr = paramErr;
  231.         
  232. cleanup:
  233.     return theErr;
  234. }
  235.  
  236.  
  237. /*************************************************************************************
  238. DeleteGraphicFromList
  239.     
  240. This routine removes the graphic from the list.  If the list is then empty,
  241. it disposes of the handle.
  242. *************************************************************************************/
  243. OSStatus DeleteGraphicFromList (UInt32 index)
  244. {
  245.     OSStatus theErr = noErr;
  246.     
  247. #if qDebugging
  248.     if ((index < 0) || (index > gNumberGraphics-1))
  249.         SIGNAL_ERROR ("\pError: Attempted to delete outside of the list.")
  250. #endif
  251.     
  252.     gNumberGraphics--;
  253.     
  254.     // If there are elements in the list, slide them up and shrink the handle
  255.     if (gNumberGraphics > 0)
  256.     {
  257.         BlockMoveData(    (*(TGraphic ***)gTGraphicList)+index+1,
  258.                         (*(TGraphic ***)gTGraphicList)+index,
  259.                         (gNumberGraphics - index) * sizeof(TGraphic *));
  260.  
  261.         SetHandleSize((Handle) gTGraphicList,gNumberGraphics*sizeof(TGraphic *));
  262.         theErr = MemError();
  263.         FAIL_OSERR (theErr, "\pCouldn't resize the list handle")
  264.         FAIL_NIL (gTGraphicList, "\pCouldn't resize the list handle")
  265.     }
  266.     else
  267.     // Otherwise, the list is empty and we can dispose of it.
  268.     {
  269.         DisposeHandle (gTGraphicList);
  270.         gTGraphicList = NULL;
  271.     }
  272.     
  273.     // We succeeded, cleanup and exit.
  274.     goto cleanup;
  275.     
  276. error:
  277.     if (theErr == noErr)
  278.         theErr = paramErr;
  279. cleanup:
  280.     return theErr;
  281. }
  282.  
  283.  
  284. /*************************************************************************************
  285. SearchGraphicList
  286.  
  287. This routine searches for a TGraphic with the resID parameter.  If it doesn't find
  288. one, the index it returns is the location where the new element should be inserted
  289. into the list.
  290. *************************************************************************************/
  291. OSStatus SearchGraphicList (SInt16 resID, Boolean *found, UInt32 *index)
  292. {    
  293.     OSStatus theErr = noErr;
  294.     UInt32 low = 0;
  295.     UInt32 high = gNumberGraphics;
  296.     UInt32 tempIndex;
  297.     SInt16 tempID;
  298.     TGraphic *theItem = NULL;
  299.     
  300.     // For an empty list, we fall through immediately.
  301.     while (low < high)
  302.     {
  303.         tempIndex = (low+high) >> 1;
  304.         theItem = (*(TGraphic ***)gTGraphicList)[tempIndex];
  305. #if qDebugging
  306.         FAIL_NIL (theItem, "\pERROR: List items should never be NULL!")
  307. #endif
  308.         tempID = theItem->GetResID();
  309.         if (resID == tempID)
  310.         {
  311.         // We found the object, return it
  312.             *found = true;
  313.             *index = tempIndex;
  314.             goto cleanup;
  315.         }
  316.         else if (resID < tempID)
  317.         // element must be below the current index
  318.             high = tempIndex;
  319.         else
  320.         // element must be above the current index
  321.             low = tempIndex+1;
  322.     }
  323.     
  324.     // We fell through, so we didn't find the item in the list.
  325.     *found = false;
  326.     *index = (low+high) >> 1;
  327.     goto cleanup;
  328.     
  329. error:
  330.     if (theErr == noErr)
  331.         theErr = paramErr;
  332.     
  333. cleanup:
  334.     return theErr;
  335. }
  336.  
  337. /*************************************************************************************
  338. TGraphic::NewGraphic
  339.  
  340. This uses the list management code to create new graphics when needed, and to manage
  341. the reference counts.
  342. *************************************************************************************/
  343. TGraphic
  344. *TGraphic::NewGraphic (SInt16 resID)
  345. {
  346.     OSStatus    theErr = noErr;
  347.     UInt32        listIndex;
  348.     Boolean     graphicAlreadyExists;
  349.     TGraphic    *newGraphic = NULL;
  350.     
  351.     theErr = SearchGraphicList (resID, &graphicAlreadyExists, &listIndex);
  352.     FAIL_OSERR(theErr,"\pERROR: Failed to search the graphic list")
  353.     
  354.     if (graphicAlreadyExists)
  355.     {
  356.         // Bump the reference count on the existing graphic
  357.         newGraphic = (*(TGraphic ***)gTGraphicList)[listIndex];
  358.         newGraphic->AddReference();
  359.     }
  360.     else
  361.     {
  362.         // Create a new graphic and insert it into the list
  363.         newGraphic = new TGraphic(resID);
  364.         theErr = newGraphic->CreateGraphic();
  365.         FAIL_OSERR(theErr,"\pERROR: Failed to create the new TGraphic.")
  366.         theErr = InsertGraphicIntoList(newGraphic, listIndex);
  367.         FAIL_OSERR(theErr, "\pERROR: Failed to insert TGraphic into list")
  368.         newGraphic->AddReference();
  369.     }
  370.     
  371.     // We succeeded, cleanup and return the TGraphic.
  372.     goto cleanup;
  373.     
  374. error:
  375.     if (newGraphic != NULL)
  376.     {
  377.         delete newGraphic;
  378.         newGraphic = NULL;
  379.     }
  380.     
  381. cleanup:    
  382.     return newGraphic;
  383. }
  384.  
  385.  
  386. /*************************************************************************************
  387. TGraphic::AddReference
  388. *************************************************************************************/
  389.  
  390. void
  391. TGraphic::AddReference (void)
  392.    {
  393.        fReferenceCount++;
  394.    }
  395.    
  396.    
  397. /*************************************************************************************
  398. TGraphic::DisposeReference
  399. *************************************************************************************/
  400.  
  401. void 
  402. TGraphic::DisposeReference (void)
  403. {
  404.        fReferenceCount--;
  405.        
  406.        // If no one cares about us, remove us from the list and delete ourself.
  407.        
  408.        if (fReferenceCount == 0)
  409.        {
  410.            UInt32                listIndex;
  411.         Boolean             tableEntry;
  412.         OSStatus            theErr = noErr;
  413.  
  414.         theErr = SearchGraphicList (fResID, &tableEntry, &listIndex);
  415. #if qDebugging
  416.         FAIL_OSERR (theErr, "\pERROR: List search reported an error")
  417.         FAIL_FALSE (tableEntry, "\pERROR: TGraphic should have been in the list!")
  418. #endif                
  419.         theErr = DeleteGraphicFromList(listIndex);
  420.         FAIL_OSERR (theErr, "\pFailed to delete graphic from the list")
  421.  
  422.            delete this;
  423.        }
  424.            
  425. error:
  426.        return;
  427. }
  428.  
  429.    
  430.    
  431. /*************************************************************************************
  432. TGraphic::TGraphic
  433.  
  434. Just puts some sane values in the member variables.
  435. *************************************************************************************/
  436. TGraphic::TGraphic (SInt16 resID)
  437. {
  438.     fResID = resID;
  439.     fReferenceCount = 0;
  440.     fImage = NULL;
  441.     fHitMask = NULL;
  442.     
  443. }
  444.  
  445.  
  446. /*************************************************************************************
  447. TGraphic::~TGraphic
  448.  
  449. If we have real, allocated graphics, we should dispose of them.
  450. *************************************************************************************/
  451. TGraphic::~TGraphic (void)
  452. {
  453.     DestroyGraphic();
  454. }
  455.  
  456.  
  457. /*************************************************************************************
  458. TGraphic::CreateGraphic
  459.  
  460. Attempt to load the graphic from a resource.  The preferred format is a pre-encoded
  461. sprite, since this loads very quickly, but if we don't find one, we'll use another
  462. format we recognize.
  463.  
  464. This is useful because you can use other graphics formats while under development.
  465. *************************************************************************************/
  466. OSStatus TGraphic::CreateGraphic(void)
  467. {
  468.     OSStatus theErr = noErr;
  469.  
  470.     theErr = LoadFromGraphicResource();
  471.     if (theErr == noErr) goto cleanup;
  472.     
  473.     theErr = LoadFromPICTResource ();
  474.     if (theErr == noErr) goto cleanup;
  475.  
  476.     theErr = LoadFromCIconResource ();
  477.     if (theErr == noErr) goto cleanup;
  478.     
  479.     theErr = LoadFromICN8Resource ();
  480.     if (theErr == noErr) goto cleanup;
  481.     
  482. error:
  483.  
  484.     SIGNAL_ERROR ("\pError: No resource was found!")
  485.     if (theErr == noErr)
  486.         theErr = paramErr;
  487.  
  488. cleanup:
  489.     return theErr;
  490.     
  491. }
  492.  
  493.  
  494. /*************************************************************************************
  495. TGraphic::DestroyGraphic
  496.     
  497. All this needs to do is dispose of the image handle we created earlier.
  498. *************************************************************************************/
  499.  
  500. OSStatus
  501. TGraphic::DestroyGraphic (void)
  502. {
  503.     if (fImage != NULL)
  504.         DisposeHandle (fImage);
  505.     if (fHitMask != NULL)
  506.         DisposeHandle (fHitMask);
  507.         
  508.     fImage = NULL;
  509.     fHitMask = NULL;
  510.     
  511.     return noErr;
  512. }
  513.  
  514.  
  515.  
  516. /*************************************************************************************
  517. TGraphic::LoadFromGraphicResource
  518.     
  519. This routine loaded a previously encoded sprite.
  520. *************************************************************************************/
  521. OSStatus TGraphic::LoadFromGraphicResource(void)
  522. {
  523.     Handle         graphicResource = NULL;
  524.     OSStatus    theErr = noErr;
  525.     Size        imageSize = 0, maskSize = 0;
  526.     TGraphicResHeaderHandle header;
  527.     
  528. // STEP 1 -- determine if the resource exists and try to load it.
  529.     graphicResource = Get1Resource (kTGraphicResourceType, fResID);
  530.     theErr = ResError();
  531.     
  532.     if ((theErr != noErr) || (graphicResource == NULL))
  533.         goto error;
  534.  
  535. // STEP 2 -- Parse the resource header
  536.     
  537.     header = (TGraphicResHeaderHandle) graphicResource;
  538.     
  539.     // This code only parses version 0 formats.
  540.     if ((**header).version != 0L)
  541.         goto error;
  542.         
  543.     fBitDepth = (**header).depth;
  544.     fFlags    = (**header).flags;
  545.     fBounds   = (**header).bounds;
  546.  
  547.     imageSize = (**header).imageSize;
  548.     maskSize =  (**header).maskSize;
  549.  
  550. // Step 3 -- Allocate the image and mask data and copy from the resource.    
  551.     fImage = NewHandle(imageSize);
  552.     theErr = MemError();
  553.     FAIL_OSERR (theErr, "\pFailed to allocate the image handle")
  554.     FAIL_NIL   (fImage, "\pFailed to allocate the image handle")
  555.     
  556.     fHitMask = NewHandle (maskSize);
  557.     theErr = MemError();
  558.     FAIL_OSERR (theErr, "\pFailed to allocate the mask handle")
  559.     FAIL_NIL   (fHitMask, "\pFailed to allocate the mask handle")
  560.     
  561.     BlockMoveData(((*graphicResource)+sizeof(TGraphicResHeader)), *fImage, imageSize);
  562.     BlockMoveData(((*graphicResource)+sizeof(TGraphicResHeader)+imageSize), *fHitMask, maskSize);
  563.     
  564. // We're done, cleanup and exit!
  565.     goto cleanup;
  566.     
  567. error:
  568.     
  569.     DestroyGraphic();
  570.     
  571.     if (theErr == noErr)
  572.         theErr = paramErr;
  573.         
  574. cleanup:
  575.     if (graphicResource != NULL)
  576.         ReleaseResource (graphicResource);
  577.     
  578.     return theErr;
  579. }
  580.  
  581.  
  582.  
  583. /*************************************************************************************
  584. TGraphic::LoadFromPICTResource
  585.     
  586. This routine reads a specially formatted pict, with image, drawing mask and hit mask
  587. going from left to right.
  588. *************************************************************************************/
  589. OSStatus
  590. TGraphic::LoadFromPICTResource (void)
  591. {
  592.     PicHandle        thePicture = NULL;
  593.     OSStatus        theErr = noErr;
  594.     GWorldPtr        graphicGWorld = NULL;
  595.     PixMapHandle    graphicPixMap = NULL;
  596.     Rect            pictRect;
  597.     
  598. // STEP 1 -- Attempt to load the PICT
  599.     thePicture = (PicHandle) Get1Resource ('PICT', fResID);
  600.     theErr = ResError();
  601.     
  602.     if ((theErr != noErr) || (thePicture == NULL))
  603.         goto error;
  604.  
  605. // STEP 2 -- Normalize the picture rectangle, and use it to build a GWorld.
  606.  
  607.     pictRect = (**thePicture).picFrame;
  608.     
  609.     pictRect.right -= pictRect.left;  pictRect.left = 0;
  610.     pictRect.bottom -= pictRect.top;  pictRect.top = 0;
  611.     
  612.     if (pictRect.right % 3 != 0)
  613.         SIGNAL_ERROR ("\pImproper size pict to load as a graphic")
  614.  
  615.     theErr = NewGWorld(&graphicGWorld, kPreferredDepth, &pictRect, gAppColorTable, NULL, keepLocal);
  616.     FAIL_OSERR (theErr, "\pCouldn't allocate GWorld for encoding")
  617.     
  618.     graphicPixMap  = GetGWorldPixMap(graphicGWorld);
  619.     FAIL_NIL (graphicPixMap, "\pCouldn't get the GWorld's PixMap")
  620.     FAIL_FALSE ( LockPixels(graphicPixMap), "\pCouldn't lock GWorld PixMap")
  621.     
  622.     // Erase the GWorld and draw our picture
  623.     {
  624.         CGrafPtr savePort;
  625.         GDHandle saveDevice;
  626.         
  627.         GetGWorld (&savePort, &saveDevice);
  628.         SetGWorld (graphicGWorld, NULL);
  629.     
  630.         EraseRect (&pictRect);
  631.         DrawPicture (thePicture, &pictRect);
  632.     
  633.         SetGWorld (savePort, saveDevice);
  634.     }
  635.  
  636. // STEP 4 -- feed the GWorld to the encoder.
  637.     
  638.     pictRect.right /=3;
  639.     theErr = EncodeGraphic (graphicPixMap, &pictRect);
  640.     
  641.     if (theErr == noErr)
  642.         goto cleanup;
  643.  
  644. error:
  645.     DestroyGraphic();
  646.         
  647.     if (theErr == noErr)
  648.         theErr = paramErr;
  649.         
  650. cleanup:
  651.     if (thePicture != NULL)
  652.         ReleaseResource ((Handle)thePicture);
  653.     
  654.     if (graphicGWorld != NULL)
  655.         DisposeGWorld (graphicGWorld);
  656.     
  657.     return theErr;
  658.  
  659. }
  660.  
  661.  
  662.  
  663. /*************************************************************************************
  664. TGraphic::LoadFromICN8Resource
  665.  
  666. This routine reads an ICL8 resource and uses the mask as both the drawing and hit
  667. mask.  It isn't quite as versatile as the PICT format, but is probably easier to
  668. find tools to build sprites with.
  669. *************************************************************************************/
  670. OSStatus
  671. TGraphic::LoadFromICN8Resource (void)
  672. {
  673.     OSStatus        theErr = noErr;
  674.     GWorldPtr        graphicGWorld = NULL;
  675.     PixMapHandle     graphicPixMap = NULL;
  676.     Rect             graphicRect = {0,0,32,96};
  677.     Rect             iconRect = {0,0,32,32};
  678.     Handle            theIconSuite = NULL;
  679.     RgnHandle        theMask = NULL;
  680.  
  681. // STEP 1 -- Attempt to load the icon
  682.     theErr = GetIconSuite(&theIconSuite, fResID, svAllAvailableData);
  683.  
  684.     if ((theErr != noErr) || (theIconSuite == NULL))
  685.         goto error;
  686.  
  687. // STEP 2 -- Create a region from the IconSuite's mask
  688.     
  689.     theMask = NewRgn();
  690.     theErr = QDError();
  691.     FAIL_OSERR (theErr, "\pError: Failed to create the mask region")
  692.     FAIL_NIL (theMask, "\pError: Failed to create the mask region")
  693.     
  694.     theErr = IconSuiteToRgn (theMask, &iconRect, atNone, theIconSuite);
  695.     FAIL_OSERR (theErr, "\pError: Failed to load the mask data into the region")
  696.     OffsetRgn (theMask, -(**theMask).rgnBBox.left, -(**theMask).rgnBBox.top);
  697.  
  698. // STEP 3 -- Create a GWorld the size of 3 ICL8s.
  699.  
  700.     theErr = NewGWorld(&graphicGWorld, kPreferredDepth, &graphicRect, gAppColorTable, NULL, keepLocal);
  701.     FAIL_OSERR (theErr, "\pCouldn't allocate GWorld for encoding")
  702.     
  703.     graphicPixMap  = GetGWorldPixMap(graphicGWorld);
  704.     FAIL_NIL (graphicPixMap, "\pCouldn't get the GWorld's PixMap")
  705.     FAIL_FALSE ( LockPixels(graphicPixMap), "\pCouldn't lock GWorld PixMap")
  706.     
  707. // STEP 4 -- Erase the GWorld and draw our icons
  708.     {
  709.         CGrafPtr savePort;
  710.         GDHandle saveDevice;
  711.         
  712.         GetGWorld (&savePort, &saveDevice);
  713.         SetGWorld (graphicGWorld, NULL);
  714.     
  715.         EraseRect (&graphicRect);
  716.         theErr = PlotIconSuite(&iconRect, atNone, ttNone, theIconSuite);  // icon
  717.         
  718.         OffsetRgn(theMask, 32, 0);
  719.         FillRgn (theMask, &qd.black); // drawing mask
  720.         OffsetRgn(theMask, 32, 0);
  721.         FillRgn (theMask, &qd.black); // hit mask
  722.  
  723.         SetGWorld (savePort, saveDevice);
  724.     }
  725.  
  726. // STEP 5 -- feed the GWorld to the encoder.
  727.     
  728.     graphicRect.right /=3;
  729.     theErr = EncodeGraphic (graphicPixMap, &graphicRect);
  730.     
  731.     if (theErr == noErr)
  732.         goto cleanup;
  733.  
  734. error:
  735.     DestroyGraphic();
  736.         
  737.     if (theErr == noErr)
  738.         theErr = paramErr;
  739.         
  740. cleanup:
  741.     if (theMask != NULL)
  742.         DisposeRgn (theMask);
  743.     if (theIconSuite != NULL)
  744.         DisposeIconSuite (theIconSuite, true);
  745.     if (graphicGWorld != NULL)
  746.         DisposeGWorld (graphicGWorld);
  747.     
  748.     return theErr;
  749.  
  750. }
  751.  
  752.  
  753. /*************************************************************************************
  754. TGraphic::LoadFromCIconResource
  755.  
  756. This is much like LoadFromICN8Resource, but loads from a CIcon instead.
  757. *************************************************************************************/
  758. OSStatus
  759. TGraphic::LoadFromCIconResource (void)
  760. {
  761.     OSStatus        theErr = noErr;
  762.     GWorldPtr        graphicGWorld = NULL;
  763.     PixMapHandle     graphicPixMap = NULL;
  764.     Rect            graphicRect, iconRect;
  765.     CIconHandle        theCIcon = NULL;
  766.     RgnHandle        theMask = NULL;
  767.     
  768. // STEP 1 -- Load the CIcon resource
  769.     theCIcon = GetCIcon (fResID);
  770.     theErr = ResError();
  771.     
  772.     if ((theCIcon == NULL) || (theErr != noErr))
  773.         goto error;
  774.  
  775. // STEP 2 -- Create a region from the Icon's mask
  776.  
  777.     theMask = NewRgn();
  778.     theErr = QDError();
  779.     FAIL_OSERR (theErr, "\pError: Failed to create the mask region")
  780.     FAIL_NIL (theMask, "\pError: Failed to create the mask region")
  781.     
  782.     // Fill in the baseAddr of the BitMap.
  783.     ( (**theCIcon).iconMask ).baseAddr = ( char* )(**theCIcon).iconMaskData;
  784.     
  785.     theErr = BitMapToRegion (theMask, &(**theCIcon).iconMask);
  786.     FAIL_OSERR (theErr, "\pFailed to load the mask data into the region")
  787.     OffsetRgn (theMask, -(**theMask).rgnBBox.left, -(**theMask).rgnBBox.top);
  788.  
  789.  
  790. // STEP 3 -- Build a GWorld the size of 3 CIcons
  791.  
  792.     iconRect = (**theCIcon).iconPMap.bounds;
  793.     iconRect.right -= iconRect.left; iconRect.left = 0;
  794.     iconRect.bottom -= iconRect.top; iconRect.top = 0;
  795.     
  796.     graphicRect = iconRect;
  797.     graphicRect.right *= 3;
  798.  
  799.     theErr = NewGWorld(&graphicGWorld, kPreferredDepth, &graphicRect, gAppColorTable, NULL, keepLocal);
  800.     FAIL_OSERR (theErr, "\pCouldn't allocate GWorld for encoding")
  801.     
  802.     graphicPixMap  = GetGWorldPixMap(graphicGWorld);
  803.     FAIL_NIL (graphicPixMap, "\pCouldn't get the GWorld's PixMap")
  804.     FAIL_FALSE ( LockPixels(graphicPixMap), "\pCouldn't lock GWorld PixMap")
  805.     
  806. // STEP 4 -- Erase the GWorld and draw our icons
  807.     {
  808.         CGrafPtr savePort;
  809.         GDHandle saveDevice;
  810.         
  811.         GetGWorld (&savePort, &saveDevice);
  812.         SetGWorld (graphicGWorld, NULL);
  813.     
  814.         EraseRect (&graphicRect);
  815.         
  816.         PlotCIcon (&iconRect, theCIcon); // image
  817.         OffsetRgn(theMask, iconRect.right, 0); 
  818.         FillRgn (theMask, &qd.black); // draw mask
  819.         OffsetRgn(theMask, iconRect.right, 0); 
  820.         FillRgn (theMask, &qd.black); // hit mask
  821.  
  822.         SetGWorld (savePort, saveDevice);
  823.     }
  824.  
  825. // STEP 5 -- feed the GWorld to the encoder.
  826.     
  827.     graphicRect.right /=3;
  828.     theErr = EncodeGraphic (graphicPixMap, &graphicRect);
  829.     
  830.     if (theErr == noErr)
  831.         goto cleanup;
  832.  
  833. error:
  834.     DestroyGraphic();
  835.         
  836.     if (theErr == noErr)
  837.         theErr = paramErr;
  838.         
  839. cleanup:
  840.     if (theMask != NULL)
  841.         DisposeRgn (theMask);
  842.     if (theCIcon != NULL)
  843.         DisposeCIcon (theCIcon);
  844.     if (graphicGWorld != NULL)
  845.         DisposeGWorld (graphicGWorld);
  846.     
  847.     return theErr;
  848.  
  849. }
  850.  
  851.  
  852.  
  853. /*************************************************************************************
  854. TGraphic::EncodeGraphic
  855.  
  856. Takes a previously prepared pixmap and compresses it into our format.
  857. *************************************************************************************/
  858. OSStatus    TGraphic::EncodeGraphic (PixMapHandle theGraphic, Rect *encodeRect)
  859. {
  860.     OSStatus theErr = noErr;
  861.     
  862.     UInt16        shapeHeight;        // the height of the shape
  863.     UInt16        shapeWidth;            // the width of the shape
  864.     
  865.     UInt32        rowBytes;            // the rowbytes of our source pixmap
  866.     UInt8        *baseAddr;            // the base address of the source pixmap
  867.     
  868.     UInt8        *dataPtr;            // points to where we are saving/encoding the data
  869.     UInt8        *sourcePtr;            // points to the graphics data we are saving in our image
  870.     UInt8        *maskPtr;            // points to whichever mask we are currently encoding
  871.     
  872.     UInt8        *sourceStartPtr;    // points to the beginning of a source row.
  873.  
  874.     UInt32        yCounter;            // a counter to scan the shape vertically
  875.     UInt32        xCounter;            // a counter to scan the shape horizontally
  876.  
  877.     Size        newSize;            // used to calculate the size of the new handle.
  878.  
  879.     // We preset the values to make the optimizer happy
  880.     UInt8        *runTokenPtr = NULL;    // where is the token for the current run
  881.     UInt32        runCounter = 0;        // how long is the current run? 
  882.  
  883. // STEP 1 -- precalculate the size of the shape.
  884. // Allocate enough memory to hold the RLE encoded shapes.
  885.  
  886.     shapeHeight = encodeRect->bottom - encodeRect->top;
  887.     shapeWidth = encodeRect->right - encodeRect->left;
  888.     
  889.     // initialize the standard member data for our shape.
  890.     fBounds.left = 0;
  891.     fBounds.top = 0;
  892.     fBounds.right = shapeWidth;
  893.     fBounds.bottom = shapeHeight;
  894.     fFlags = 0;
  895.     fBitDepth = (**theGraphic).pixelSize;
  896.     
  897.     if (fBitDepth != 8)
  898.         SIGNAL_ERROR ("\pError: This encoder only supports 8 bit images")
  899.         
  900.     //the memory totals are for the worse case shape.
  901.     
  902.     fImage = NewHandle (8*shapeHeight * shapeWidth + 4*shapeHeight +4);
  903.     theErr = MemError();
  904.     FAIL_OSERR (theErr, "\pFailed to allocate a handle for the shape data")
  905.     FAIL_NIL (fImage, "\pFailed to allocate a handle for the shape data")
  906.     
  907.     fHitMask = NewHandle (4*shapeHeight * shapeWidth + 4*shapeHeight +4);
  908.     theErr = MemError();
  909.     FAIL_OSERR (theErr, "\pFailed to allocate a handle for the hit mask data")
  910.     FAIL_NIL (fHitMask, "\pFailed to allocate a handle for the hit mask data")
  911.     
  912.     // Get some of the standard data we'll need when encoding the pixels
  913.     
  914.     baseAddr = (UInt8  *)GetPixBaseAddr( theGraphic );
  915.     rowBytes = (*theGraphic)->rowBytes & 0x3fff;
  916.  
  917.  
  918. // STEP 2 -- Encode the shape data.  We use a separate mask rather than using
  919. // chroma keying.  This was mostly done to allow more flexibility in the
  920. // image design, but the other way works very similar.
  921.     
  922.     HLock (fImage);
  923.     dataPtr = (UInt8 *) (*fImage);
  924.     
  925.     sourceStartPtr = baseAddr + rowBytes * encodeRect->top + encodeRect->left;
  926.     
  927.     // scan the shape row by row
  928.     for( yCounter = 0; yCounter < shapeHeight; yCounter++ )
  929.     {
  930.         // store where the line starts, so we can fill in the lineStart token.
  931.         UInt8    *lineStartPtr = dataPtr;
  932.         
  933.         // Flags to determine which run we are currently in.  Initially false,
  934.         // we don't start in a run.
  935.         UInt8    drawRunFlag = false;                // are we in a draw pixels run?
  936.         UInt8    skipRunFlag = false;                // are we in a skip pixels run?
  937.         
  938.         // reserve space for the lineStart token.
  939.         dataPtr += sizeof( UInt32 );
  940.         
  941.         // move to the start of the row and begin scanning the pixels of the row.
  942.         sourcePtr = sourceStartPtr;
  943.         maskPtr = sourceStartPtr + shapeWidth;
  944.             
  945.         for( xCounter = 0; xCounter < shapeWidth; xCounter++ )
  946.         {
  947.             if ( *maskPtr == kClearColorIndex )
  948.             {
  949.                 // Finish the draw run if we are in one.
  950.                 if ( drawRunFlag )
  951.                 {
  952.                     drawRunFlag = false;
  953.                                     
  954.                     // create the draw token, and pad the line to a multiple of four.
  955.                     *( (UInt32 *)runTokenPtr ) = ( kDrawPixelsToken << 24 ) + runCounter;
  956.                                     
  957.                     *( (UInt32 *)dataPtr ) = 0L;
  958.                     dataPtr = (UInt8 *) ALIGN_TO_NEXT_LONG(dataPtr);
  959.                 }
  960.                             
  961.                 // Start a new skip run, or continue the existing one.
  962.                 if ( skipRunFlag )
  963.                 {
  964.                     runCounter++;
  965.                 }
  966.                 else
  967.                 {
  968.                     // start a new skip run
  969.                     skipRunFlag = true;
  970.                     runCounter = 1;
  971.                 }
  972.             }
  973.             else
  974.             {
  975.                 // Finish the skip run, if we're in one.
  976.                 if ( skipRunFlag )
  977.                 {
  978.                     skipRunFlag = false;
  979.                     
  980.                     // create the skip token
  981.                     *( ( UInt32 * )dataPtr ) = ( kSkipPixelsToken << 24 ) + runCounter;
  982.                     dataPtr += sizeof( UInt32 );
  983.                 }
  984.                 
  985.                 // Start a new draw run, or continue the existing one.
  986.                 if ( drawRunFlag )
  987.                 {
  988.                     // continue it
  989.                     runCounter++;
  990.                                     
  991.                     // copy the pixel
  992.                     *dataPtr = *sourcePtr;
  993.                     dataPtr++;
  994.                 }
  995.                 else
  996.                 {
  997.                     // start one
  998.                     drawRunFlag = true;
  999.                     runCounter = 1;
  1000.                                     
  1001.                     // save the location of the token (so we can fill it in later)
  1002.                     runTokenPtr = dataPtr;
  1003.                     dataPtr += sizeof( UInt32 );
  1004.                                     
  1005.                     // copy the pixel
  1006.                     *dataPtr = *sourcePtr;
  1007.                     dataPtr++;
  1008.                 }
  1009.             }
  1010.                     
  1011.             // move to the next pixel
  1012.             sourcePtr++;
  1013.             maskPtr++;
  1014.         }
  1015.         
  1016.         // no need to write a skip at the end of a line, but we do need to finish
  1017.         // up a draw run if that's what we were working on.
  1018.         if( drawRunFlag )
  1019.         {
  1020.             // create the draw token
  1021.             *((UInt32 *) runTokenPtr) = ( kDrawPixelsToken << 24 ) + runCounter;
  1022.                                     
  1023.             // clear and pad to a mulitple of four
  1024.             *((UInt32 *)dataPtr ) = 0L;
  1025.             dataPtr = (UInt8 *) ALIGN_TO_NEXT_LONG(dataPtr);
  1026.         }
  1027.         
  1028.         // finish the line start token, and move to the next row.
  1029.         *( (UInt32 *)lineStartPtr ) = ( kLineStartToken << 24 ) + ( dataPtr - ( lineStartPtr + 4 ) );
  1030.         sourceStartPtr += rowBytes;
  1031.     }
  1032.     
  1033.     // create the end of shape token
  1034.     *((UInt32 *) dataPtr) = kEndShapeToken << 24;
  1035.     dataPtr += sizeof( UInt32 );
  1036.  
  1037.     // Resize the handle to match the real size of the shape
  1038.     HUnlock( fImage );
  1039.     newSize = dataPtr - (UInt8 *)( *fImage );
  1040.     SetHandleSize( fImage, newSize );
  1041.     theErr = MemError();
  1042.     FAIL_OSERR (theErr, "\p Failed to resize the handle")
  1043.     
  1044. // STEP 3-- Encode the Mask data.  Unlike the previous encoder, we don't have to copy any pixel
  1045. // data.
  1046.  
  1047.     HLock (fHitMask);
  1048.     dataPtr = (UInt8 *)( *fHitMask );
  1049.     
  1050.     sourceStartPtr = baseAddr + rowBytes * encodeRect->top + encodeRect->left + shapeWidth+shapeWidth;
  1051.     
  1052.     // scan the shape row by row
  1053.     for( yCounter = 0; yCounter < shapeHeight; yCounter++ )
  1054.     {
  1055.         // we need to store where this line starts so we can fill in the lineStart token later.
  1056.         UInt8    *lineStartPtr = dataPtr;
  1057.         UInt8    drawRunFlag = false;                // are we in a draw pixels run?
  1058.         UInt8    skipRunFlag = false;                // are we in a skip pixels run?
  1059.         
  1060.         // reserve a place for the line start token.
  1061.         dataPtr += sizeof( UInt32 );
  1062.         maskPtr = sourceStartPtr;
  1063.             
  1064.         // scan each pixel of the mask.
  1065.         for( xCounter = 0; xCounter < shapeWidth; xCounter++ )
  1066.         {
  1067.             // is this pixel clear?
  1068.             if ( *maskPtr == kClearColorIndex )
  1069.             {
  1070.                 // are we in a draw run?
  1071.                 if ( drawRunFlag )
  1072.                 {
  1073.                     // end the draw run
  1074.                     drawRunFlag = false;
  1075.                                     
  1076.                     // create the draw token
  1077.                     *( (UInt32 *)dataPtr ) = ( kDrawPixelsToken << 24 ) + runCounter;
  1078.                     dataPtr += sizeof( UInt32 );
  1079.                 }
  1080.                             
  1081.                 // are we in a skip run
  1082.                 if ( skipRunFlag )
  1083.                 {
  1084.                 // continue it
  1085.                     runCounter++;
  1086.                 }
  1087.                 else
  1088.                 {
  1089.                     // start one
  1090.                     skipRunFlag = true;
  1091.                     runCounter = 1;
  1092.                 }
  1093.             }
  1094.             else
  1095.             {
  1096.             // are we in a skip run
  1097.                 if ( skipRunFlag )
  1098.                 {
  1099.                     // end the skip run
  1100.                     skipRunFlag = false;
  1101.                     // create the skip token
  1102.                     *( (UInt32 *)dataPtr ) = ( kSkipPixelsToken << 24 ) + runCounter;
  1103.                     dataPtr += sizeof( UInt32 );
  1104.                 }
  1105.                             
  1106.                 // are we in a draw run
  1107.                 if ( drawRunFlag )
  1108.                 {
  1109.                     // continue it
  1110.                     runCounter++;
  1111.                 }
  1112.                 else
  1113.                 {
  1114.                     // start one
  1115.                     drawRunFlag = true;
  1116.                     runCounter = 1;
  1117.                 }
  1118.             }
  1119.                     
  1120.             // move to the next byte
  1121.                     maskPtr++;
  1122.         }
  1123.         
  1124.         // if we're finishing up a draw run, we need to write out the token
  1125.  
  1126.         if( drawRunFlag )
  1127.         {
  1128.             *( (UInt32 *)dataPtr ) = ( kDrawPixelsToken << 24 ) + runCounter;
  1129.             dataPtr += sizeof( UInt32 );
  1130.         }
  1131.             
  1132.         // create the line start token
  1133.         *( (UInt32 *)lineStartPtr ) = ( kLineStartToken << 24 ) + ( dataPtr - ( lineStartPtr + 4 ) );
  1134.             
  1135.         // move the row start to the next row
  1136.         sourceStartPtr += rowBytes;
  1137.     }
  1138.     
  1139.     // create the end of shape token
  1140.     *( (UInt32 *)dataPtr ) = kEndShapeToken << 24;
  1141.     dataPtr += sizeof( UInt32 );
  1142.     
  1143.     
  1144.     
  1145.     // Resize the handle to match the real size of the shape
  1146.     HUnlock( fHitMask );
  1147.     newSize = dataPtr - (UInt8 *)( *fHitMask );
  1148.     SetHandleSize( fHitMask, newSize );
  1149.     theErr = MemError();
  1150.     FAIL_OSERR (theErr, "\p Failed to resize the handle")
  1151.  
  1152.     goto cleanup;
  1153.  
  1154. error:
  1155.     
  1156.     if (theErr == noErr)
  1157.         theErr = paramErr;
  1158.         
  1159. cleanup:
  1160.     // cleanup is actually the responsibility of the calling function.
  1161.     return theErr;
  1162. }
  1163.     
  1164.     
  1165.  
  1166. /*************************************************************************************
  1167. TGraphic::WriteToGraphicResource
  1168.     
  1169. This takes a previously created graphic and writes out our custom resource format.
  1170. *************************************************************************************/
  1171. OSStatus
  1172. TGraphic::WriteToGraphicResource (void)
  1173. {
  1174.     Handle    graphicResource = NULL;
  1175.     OSStatus    theErr;
  1176.     Size imageSize;
  1177.     Size maskSize;
  1178.     
  1179.     imageSize = GetHandleSize(fImage);
  1180.     theErr = MemError();
  1181.     FAIL_OSERR (theErr, "\pCouldn't obtain image handle size")
  1182.     
  1183.     maskSize = GetHandleSize (fHitMask);
  1184.     theErr = MemError();
  1185.     FAIL_OSERR (theErr, "\pCouldn't obtain mask handle size")
  1186.     
  1187.     graphicResource = NewHandle (sizeof(TGraphicResHeader) + imageSize + maskSize);
  1188.     theErr = MemError();
  1189.     FAIL_OSERR (theErr, "\pCouldn't allocate handle to hold new resource")
  1190.     FAIL_NIL (graphicResource, "\pCouldn't allocate handle to hold new resource")
  1191.     
  1192.     // Now to fill in the header and block move all of the data over into the new resource.
  1193.     
  1194.     (**(TGraphicResHeaderHandle)graphicResource).version   = 0L;
  1195.     (**(TGraphicResHeaderHandle)graphicResource).depth     = fBitDepth;
  1196.     (**(TGraphicResHeaderHandle)graphicResource).flags     = fFlags;
  1197.     (**(TGraphicResHeaderHandle)graphicResource).bounds    = fBounds;
  1198.     (**(TGraphicResHeaderHandle)graphicResource).imageSize = imageSize;
  1199.     (**(TGraphicResHeaderHandle)graphicResource).maskSize  = maskSize;
  1200.     
  1201.     BlockMoveData(*fImage, ((*graphicResource)+sizeof(TGraphicResHeader)), imageSize);
  1202.     BlockMoveData(*fHitMask, ((*graphicResource)+sizeof(TGraphicResHeader)+imageSize), maskSize);
  1203.     
  1204.     // **TO DO:  Check to see if there is already a resource with that ID!
  1205.     
  1206.     // Add the resource to the file.
  1207.     AddResource( graphicResource, kTGraphicResourceType, fResID, "\p" );
  1208.     theErr = ResError();
  1209.     FAIL_OSERR (theErr, "\pFailed to add the TGraphic resource to the file")
  1210.     
  1211.     WriteResource( graphicResource );
  1212.     theErr = ResError();
  1213.     FAIL_OSERR (theErr, "\pError: Failed to write the resource")
  1214.     
  1215.     UpdateResFile (CurResFile());
  1216.     theErr = ResError();
  1217.     
  1218.     ReleaseResource( graphicResource );
  1219.     
  1220.     return theErr;
  1221.     
  1222. error:
  1223.     if (graphicResource != NULL)
  1224.         DisposeHandle (graphicResource);
  1225.     if (theErr == noErr)
  1226.         theErr = paramErr;
  1227.         
  1228.     return theErr;
  1229. }
  1230.  
  1231.  
  1232.  
  1233. /*************************************************************************************
  1234. TGraphic::WriteToPICTResource
  1235.     
  1236. This takes a previously created graphic and writes out a PICT with the 3 images.
  1237. *************************************************************************************/
  1238. OSStatus
  1239. TGraphic::WriteToPICTResource (void)
  1240. {    
  1241.     Rect            pictRect = fBounds;
  1242.     OSStatus        theErr = NULL;
  1243.     GWorldPtr        graphicGWorld = NULL;
  1244.     PixMapHandle     graphicPixMap = NULL;
  1245.     PicHandle        thePicture = NULL;
  1246.         
  1247.     // Create a locked GWorld with the proper depth, dimensions and color table.
  1248.     pictRect.right += (pictRect.right+pictRect.right);
  1249.     
  1250.     theErr = NewGWorld(&graphicGWorld, kPreferredDepth, &pictRect, gAppColorTable, NULL, keepLocal);
  1251.     FAIL_OSERR (theErr, "\pCouldn't allocate GWorld for encoding")
  1252.     graphicPixMap  = GetGWorldPixMap(graphicGWorld);
  1253.     FAIL_NIL (graphicPixMap, "\pCouldn't get the GWorld's PixMap")
  1254.     FAIL_FALSE ( LockPixels(graphicPixMap), "\pCouldn't lock GWorld PixMap")
  1255.     
  1256.     // Erase the GWorld to white and draw the graphics into it.
  1257.     // HACK alert -- this code knows way too much about the information saved off in scaling.cp.
  1258.     // The real way to do this is to have some sort of structure analogous to a grafPort, and
  1259.     // switch the existing destination that way.  Was slated for 1.1, but if that doesn't
  1260.     // happen, I'll move it back into this code.
  1261.     
  1262.     {
  1263.         CGrafPtr savePort;
  1264.         GDHandle saveDevice;
  1265.         
  1266.         Rect             saveRect             = gClipRect;
  1267.         PixMapHandle    saveDestPixMap        = gDestPixMap;
  1268.         PixMapHandle    saveBackPixMap        = gBackPixMap;
  1269.         UInt8            *saveDestBaseAddr    = gDestBaseAddr;
  1270.         UInt8            *saveBackBaseAddr    = gBackBaseAddr;
  1271.         UInt32            saveRowBytes        = gRowBytes;
  1272.  
  1273.         SInt32            top, left;
  1274.         OpenCPicParams    pictParams;
  1275.                 
  1276.         GetGWorld (&savePort, &saveDevice);
  1277.         SetGWorld (graphicGWorld, NULL);
  1278.         
  1279.         ClipRect (&pictRect);
  1280.         EraseRect (&pictRect);
  1281.                 
  1282.         SetDestinationBuffer (graphicPixMap, NULL);
  1283.  
  1284.         // finally, we draw the three images
  1285.         top = fBounds.top;
  1286.         left = fBounds.left;
  1287.         
  1288.         GraphicUnclipped (top, left);
  1289.         left += fBounds.right;
  1290.         DrawMaskUnclipped (top, left);
  1291.         left += fBounds.right;
  1292.         HitMaskUnclipped (top, left);
  1293.         
  1294.         // restore everything 
  1295.         
  1296.         gClipRect = saveRect;
  1297.         gDestPixMap = saveDestPixMap;
  1298.         gBackPixMap = saveBackPixMap;
  1299.         gDestBaseAddr = saveDestBaseAddr;
  1300.         gBackBaseAddr = saveBackBaseAddr;
  1301.         gRowBytes = saveRowBytes;
  1302.         
  1303.         // create the pict
  1304.         pictParams.srcRect = pictRect;
  1305.         pictParams.hRes = 0x00480000;
  1306.         pictParams.vRes = 0x00480000;
  1307.         pictParams.version = -2;
  1308.         pictParams.reserved1 = 0;
  1309.         pictParams.reserved2 = 0;
  1310.         
  1311.         thePicture = OpenCPicture (&pictParams);
  1312.         
  1313.         ClipRect(&pictRect);
  1314.         CopyBits ((BitMap *) *graphicPixMap, (BitMap *) *graphicPixMap, 
  1315.                     &pictRect, &pictRect, srcCopy, NULL);
  1316.         
  1317.         ClosePicture();
  1318.         theErr = QDError();
  1319.         
  1320.         SetGWorld (savePort, saveDevice);
  1321.     }
  1322.     
  1323.     FAIL_NIL (thePicture, "\p Couldn't open the new picture")
  1324.     FAIL_OSERR (theErr, "\pFailed to create new picture")
  1325.     
  1326.     // Add the PICT to the resource fork.
  1327.     
  1328.     AddResource( (Handle) thePicture, 'PICT', fResID, "\p" );
  1329.     theErr = ResError();
  1330.     FAIL_OSERR (theErr, "\pFailed to add the PICT resource to the file")
  1331.     
  1332.     WriteResource( (Handle) thePicture );
  1333.     FAIL_OSERR (theErr, "\pError: Failed to write the resource")
  1334.     
  1335.     UpdateResFile (CurResFile());
  1336.     theErr = ResError();
  1337.     FAIL_OSERR (theErr, "\pError: Failed to update the resource fork")
  1338.     
  1339.     goto cleanup;
  1340.  
  1341. error:
  1342.     if (theErr == noErr)
  1343.         theErr = paramErr;
  1344.         
  1345.  
  1346. cleanup:
  1347.     if (graphicGWorld != NULL)
  1348.         DisposeGWorld (graphicGWorld);
  1349.     
  1350.     if (thePicture != NULL)
  1351.     {
  1352.         SInt8    memState = HGetState((Handle)thePicture);
  1353.         if (memState & 0x20)
  1354.             ReleaseResource ((Handle) thePicture);
  1355.         else
  1356.             DisposeHandle ((Handle) thePicture);
  1357.     }
  1358.     
  1359.     return theErr;
  1360.  
  1361. }
  1362.  
  1363.  
  1364.  
  1365. /*************************************************************************************
  1366. TGraphic::LockGraphic
  1367.  
  1368. Move all fo the data high and lock it down in memory.
  1369. *************************************************************************************/
  1370. OSStatus
  1371. TGraphic::LockGraphic (void)
  1372. {
  1373.     OSStatus theErr;
  1374.     MoveHHi (fImage);
  1375.     theErr = MemError();
  1376.     FAIL_OSERR (theErr, "\pFailed to move the draw data high")
  1377.     HLock (fImage);
  1378.     theErr = MemError();
  1379.     FAIL_OSERR (theErr, "\pFailed to lock the draw data")
  1380.  
  1381.     MoveHHi (fHitMask);
  1382.     theErr = MemError();
  1383.     FAIL_OSERR (theErr, "\pFailed to move the mask data high")
  1384.     HLock (fHitMask);
  1385.     theErr = MemError();
  1386.     FAIL_OSERR (theErr, "\pFailed to lock the mask data")    
  1387.     return noErr;
  1388.     
  1389.     error:
  1390.     return theErr;
  1391. }
  1392.  
  1393.  
  1394. /*************************************************************************************
  1395. TGraphic::UnlockGraphic
  1396.     
  1397. Unlock the previously locked memory.
  1398. *************************************************************************************/
  1399.  
  1400. OSStatus
  1401. TGraphic::UnlockGraphic (void)
  1402. {
  1403.     OSStatus theErr;
  1404.     HUnlock (fImage);
  1405.     theErr = MemError();
  1406.     FAIL_OSERR (theErr, "\pFailed to unlock the draw data")
  1407.     HUnlock (fHitMask);
  1408.     theErr = MemError();
  1409.     FAIL_OSERR (theErr, "\pFailed to unlock the draw data")    
  1410.     return noErr;
  1411.     
  1412.     error:
  1413.     
  1414.     return theErr;
  1415. }
  1416.  
  1417.  
  1418.  
  1419.  
  1420.  
  1421.  
  1422. /*************************************************************************************
  1423. TGraphic::CopyImage
  1424.  
  1425. This routine checks against the clipping rectangle and dispatches to the correct
  1426. utility routine.
  1427. *************************************************************************************/
  1428. void
  1429. TGraphic::CopyImage (SInt32 top, SInt32 left, Boolean useBackground)
  1430. {
  1431. #if qDebugging
  1432.     if (gDestPixMap == NULL)
  1433.         SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap")
  1434.         
  1435.     if (useBackground && (gBackPixMap == NULL))
  1436.         SIGNAL_ERROR ("\pAttepting to draw from an NULL background pixmap.")
  1437.         
  1438.     if (EmptyRect (&gClipRect))
  1439.         SIGNAL_ERROR ("\pEmpty Clipping Region")
  1440. #endif
  1441.     // We'll do all our calculations in variables rather than use a structure.
  1442.     // hopefully this should speed things up
  1443.     SInt32 destTop, destBottom, destLeft, destRight;
  1444.     
  1445.     destTop    = fBounds.top + top;
  1446.     destBottom = fBounds.bottom + top;
  1447.     destLeft   = fBounds.left + left;
  1448.     destRight  = fBounds.right + left;
  1449.     
  1450.     // determine if the spite needs to be drawn at all
  1451.     if    (destTop >= gClipRect.bottom || destBottom <= gClipRect.top ||
  1452.          destLeft >= gClipRect.right || destRight <= gClipRect.left )
  1453.         // no need to draw, goodbye
  1454.         return;
  1455.     
  1456.     // determine if the sprite will be clipped
  1457.     if     (destTop < gClipRect.top || destBottom > gClipRect.bottom ||
  1458.          destLeft < gClipRect.left || destRight > gClipRect.right)
  1459.     {
  1460.         // calculate the clipped bounding box in object local coordinates
  1461.         UInt32 clipTop, clipBottom, clipLeft, clipRight;
  1462.                 
  1463.         clipTop    = destTop < gClipRect.top       ? gClipRect.top - destTop  : 0;
  1464.         clipBottom = destBottom > gClipRect.bottom ? gClipRect.bottom-destTop : destBottom-destTop;
  1465.         clipLeft   = destLeft < gClipRect.left     ? gClipRect.left-destLeft  : 0;
  1466.         clipRight  = destRight > gClipRect.right   ? gClipRect.right-destLeft : destRight-destLeft;
  1467.  
  1468.         if (useBackground)
  1469.             BackgroundClipped (destTop, destLeft, clipLeft, clipRight, clipTop, clipBottom);
  1470.         else
  1471.             GraphicClipped(destTop, destLeft, clipLeft, clipRight, clipTop, clipBottom );
  1472.     }
  1473.     else
  1474.     {
  1475.         if (useBackground)
  1476.             BackgroundUnclipped (destTop, destLeft);
  1477.         else
  1478.             GraphicUnclipped(destTop, destLeft );
  1479.     }
  1480.  
  1481. error:
  1482.     return;
  1483. }
  1484.  
  1485.  
  1486. /*************************************************************************************
  1487. TGraphic::HitTest
  1488.     
  1489. This code walks the mask and returns true if the point intersects inside the mask.
  1490.  
  1491. We make sure the point is inside the rectangle.  If it in, we find the line in the
  1492. shape that corresponds to that point and walk it, looking for lines inside the mask.
  1493.  
  1494. Note that on the right side, we test greater than or equal, and on the left we only
  1495. test less than.  This is because the point that corresponds to a coord goes down and
  1496. to the left.  Think about it and you'll understand. :-)
  1497. *************************************************************************************/
  1498. Boolean
  1499. TGraphic::HitTest (SInt32 v, SInt32 h)
  1500. {    
  1501.     if( v >= fBounds.bottom || v < fBounds.top ||
  1502.         h >= fBounds.right || h < fBounds.left )
  1503.     {
  1504.         return false;
  1505.     }
  1506.     
  1507.     // Our standard things to read the sprite
  1508.     UInt8 *dataPtr;
  1509.     UInt32 tokenOp;
  1510.     UInt32 tokenData;
  1511.     
  1512.     // We use these to count where we are in the image, to move to our point.
  1513.         
  1514.     UInt32 yCount = 0;
  1515.     UInt32 xCount = 0; 
  1516.     
  1517.     // Move to the start of our hit testing data
  1518.     dataPtr = (UInt8 *)(*fHitMask);
  1519.  
  1520.     // Do a quick walk to the line which holds the point.
  1521.     while (v > 0)
  1522.     {
  1523.         v--;
  1524.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  1525.             
  1526.         dataPtr += sizeof( UInt32 );
  1527.         dataPtr += tokenData;
  1528.     }
  1529.     
  1530.     // Skip the newLine token
  1531.     dataPtr += sizeof( UInt32 );
  1532.         
  1533.     // Start reading draw commands.  Any end or newLine tokens mean we're done.
  1534.     // We'll exit out of the While loop via a return.
  1535.     do 
  1536.     {
  1537.         // get a token
  1538.         tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
  1539.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  1540.         dataPtr += sizeof( UInt32 );
  1541.             
  1542.         // depending on the token, we take an action
  1543.         
  1544.         // Note that line starts will be very common to begin with, so we'll move them up to the top
  1545.         switch( tokenOp )
  1546.         {
  1547.             case kHitTestPixelsToken:
  1548.  
  1549.     // We can only generate a hit in a draw command.  If our point is between
  1550.     // xCount and xCount+tokenData, then it is on a drawn line, so return true.
  1551.                 if ((xCount <= h) && (xCount+tokenData>h))
  1552.                     return true;
  1553.                 else if (xCount > h)
  1554.                     return false;
  1555.                 xCount += tokenData;
  1556.                 
  1557.                 break;
  1558.                     
  1559.             case kSkipPixelsToken:
  1560.                     
  1561.                 xCount += tokenData;
  1562.                         
  1563.                 if (xCount > h)
  1564.                     return false;
  1565.                             
  1566.                 break;
  1567.                     
  1568.             case kLineStartToken:
  1569.             case kEndShapeToken:
  1570.                 return false;
  1571. #if qDebugging        
  1572.             default:
  1573.                 SIGNAL_ERROR ("\pInvalid TGraphic drawing operation")
  1574.                 break;
  1575. #endif
  1576.         }
  1577.     } while ( true );
  1578.  
  1579. error:
  1580. return false;
  1581. }
  1582.  
  1583.  
  1584.  
  1585. /*************************************************************************************
  1586. TGraphic::Intersect
  1587.     
  1588. This compares two TGraphic objects and two points in the SAME coordinate system
  1589. and returns true if any two drawing commands intersect in the two objects.
  1590. *************************************************************************************/
  1591.  
  1592.  
  1593. Boolean TGraphic::Intersect (TGraphic *object1, TGraphic *object2, SInt32 v1, SInt32 h1, SInt32 v2, SInt32 h2)
  1594. {
  1595.     SInt32         differenceX, differenceY;
  1596.     
  1597.     SInt32        object1right, object1bottom;
  1598.     SInt32        object2top, object2bottom, object2left, object2right;
  1599.     
  1600.     UInt32        xIntersectLeft, xIntersectRight, yHeight;
  1601.     
  1602.     Boolean        intersect = false;
  1603.     
  1604.     // First, we sort the two objects in order of the x coordinate.
  1605.     
  1606.     if (h2 < h1)
  1607.     {
  1608.         SInt32 tempNum;
  1609.         TGraphic *tempGraphic;
  1610.         
  1611.         tempGraphic = object1; object1 = object2; object2 = tempGraphic;
  1612.  
  1613.         tempNum = h2; h2 = h1; h1 = tempNum;
  1614.         tempNum = v2; v2 = v1; v1 = tempNum;
  1615.     }
  1616.  
  1617.     // Next we calculate the bounding boxes of the two graphics and check to see if they overlap.
  1618.     // if they don't we can drop out and exit.
  1619.     
  1620.     differenceX = h2-h1;
  1621.     differenceY = v2-v1;
  1622.     // create two rectangles based on the object locations.
  1623.     
  1624.     object1right = (object1->fBounds).right;
  1625.     object1bottom = (object1->fBounds).bottom;
  1626.     
  1627.     object2left = differenceX;
  1628.     object2right = object2->fBounds.right + differenceX;
  1629.     object2top = differenceY;
  1630.     object2bottom = object2->fBounds.bottom + differenceY;
  1631.  
  1632.     if (object2bottom <= 0 || object2top >= object1bottom ||
  1633.         object2left >= object1right)
  1634.         goto done;
  1635.  
  1636.     // Next we want to do some calculations that we'll use to parse the list.  Basically, we are
  1637.     // determining the coordinates we're going to use for to search for an intersection.
  1638.     
  1639.     xIntersectLeft = object2left;
  1640.     xIntersectRight = object1right > object2right  ? object2right  :  object1right;
  1641.     
  1642.     {
  1643.         UInt32 yTop, yBottom;
  1644.     
  1645.         yTop    = object2top    > 0             ? object2top     :     0;
  1646.         yBottom = object1bottom > object2bottom ? object2bottom  :     object1bottom;
  1647.  
  1648.         yHeight = yBottom-yTop; // the number of row's we'll need to test.
  1649.     }
  1650.             
  1651. // These will hold whichever command we are looking at.
  1652.     UInt32 tokenOp;
  1653.     UInt32 tokenData;
  1654.     
  1655.     // These will hold our current pointers to commands for both objects.
  1656.     UInt8 *dataPtr1, *dataPtr2;
  1657.     
  1658.     // We'll precalculate the pointers for the next line, to make it easier to change
  1659.     // both objects at the same time.
  1660.     
  1661.     UInt8 *nextDataPtr1, *nextDataPtr2;
  1662.     
  1663.     // Whenever we hit an end of line, we need to drop out and make sure both data pointers are incremented.
  1664.         
  1665.     UInt8 lineDone = false;
  1666.     
  1667.     // We occasionally need to drop out of just the inner loop -- we'll set this to true.
  1668.     
  1669.     UInt8 innerObjectDone = false;
  1670.     
  1671.     // These count where we're at in each of the two object's scanlines.
  1672.     
  1673.     UInt32 xCount1 = 0, xCount2 = 0;
  1674.  
  1675.  
  1676.  
  1677.     // move to the start of each shape's data.
  1678.     dataPtr1 = (UInt8 *)(*(object1->fHitMask));
  1679.     dataPtr2 = (UInt8 *)(*(object2->fHitMask));
  1680.  
  1681.     // One of the two objects will probably need to be advanced in the vertical coordinate to put us
  1682.     // in the correct position.  We'll count out a number of skips equal to the previous y difference
  1683.     // we calculated.
  1684.     // now we need to skip lines until we get to the correct starting location for each shape.
  1685.     // With the current encoder, all objects start with startline commands.  So we'll cound out a number
  1686.     // of skips equal to the intersection rect's top Y coordinate.
  1687.     if (differenceY > 0)
  1688.         do
  1689.         {
  1690.             tokenData = ( *( (UInt32 *)dataPtr1 ) ) & 0x00ffffff;
  1691.             
  1692.             dataPtr1 += sizeof( UInt32 );
  1693.             dataPtr1 += tokenData;
  1694.         }
  1695.         while (--differenceY > 0);
  1696.     else
  1697.         while (differenceY++ < 0)
  1698.         {
  1699.             tokenData = ( *( (UInt32 *)dataPtr2 ) ) & 0x00ffffff;
  1700.             
  1701.             dataPtr2 += sizeof( UInt32 );
  1702.             dataPtr2 += tokenData;
  1703.         }
  1704.     // Now we're ready to begin.  For the most part, we loop inside object1 looking for a draw command
  1705.     // inside the intersected area.  If we find one, then we run a second loop inside this, looking
  1706.     // for a draw commmand in object2 that intersects the one from object1.  If we find one, we return
  1707.     // true.  If we hit the end of the shape, or the intersected area, we return false.
  1708.     
  1709.     // If we hit the end of a particular line, then we drop out of both loops and advance the pointers
  1710.     // appropriately, and run the next line.
  1711.     
  1712.     do 
  1713.     {
  1714.     // First, we retrieve the start of line command for each of the objects -- from this we can
  1715.     // calculate the pointers for the next scanline, which we use when we drop out of the search
  1716.     // loops.  
  1717.         tokenOp = ( *( (UInt32 *)dataPtr1 ) ) >> 24;
  1718.         tokenData = ( *( (UInt32 *)dataPtr1 ) ) & 0x00ffffff;
  1719.             
  1720.         dataPtr1 += sizeof( UInt32 );
  1721.         nextDataPtr1 = dataPtr1+ tokenData;
  1722.         
  1723.         tokenOp = ( *( (UInt32 *)dataPtr2 ) ) >> 24;
  1724.         tokenData = ( *( (UInt32 *)dataPtr2 ) ) & 0x00ffffff;
  1725.             
  1726.         dataPtr2 += sizeof( UInt32 );
  1727.         nextDataPtr2 = dataPtr2+ tokenData;
  1728.         
  1729.         // reset our booleans and our horizontal positions.
  1730.         lineDone = false;
  1731.         xCount1 = 0;
  1732.         xCount2 = xIntersectLeft;
  1733.         
  1734.  
  1735.         
  1736.         while (!lineDone)
  1737.         {
  1738.         // Loop in object1 looking for a draw command inside the intersected area.  If we hit the end
  1739.         // of our intersected area or a new line token, we'll drop out of the loop.
  1740.         // Get the next operation
  1741.             tokenOp = ( *( (UInt32 *)dataPtr1 ) ) >> 24;
  1742.             tokenData = ( *( (UInt32 *)dataPtr1 ) ) & 0x00ffffff;
  1743.             
  1744.             dataPtr1 += sizeof( UInt32 );
  1745.         
  1746.             switch (tokenOp)
  1747.             {
  1748.                 case kHitTestPixelsToken:
  1749.                     // kDrawPixels is the ugly token to parse, because if the drawing command
  1750.                     // is inside the intersected area, we have to run ANOTHER loop for object 2.
  1751.                     {
  1752.                     UInt32 x1RightDraw = xCount1+tokenData;
  1753.                     UInt32 x1LeftDraw = xCount1;
  1754.                     // skip to next command
  1755.                     
  1756.                     // if we're still to the left of our intersection, skip to next set
  1757.                     if (x1RightDraw <= xIntersectLeft)
  1758.                         break;
  1759.                         
  1760.                     // pin left side to intersection
  1761.                     if (x1LeftDraw < xIntersectLeft)
  1762.                         x1LeftDraw = xIntersectLeft;
  1763.                         
  1764.                     // pin to right side to intersection
  1765.                     if (x1RightDraw > xIntersectRight)
  1766.                         x1RightDraw = xIntersectRight;
  1767.                     
  1768.                     // Now we loop inside of object 2 until we find an intersecting draw command
  1769.                     // or skip past object1's draw area.
  1770.                     innerObjectDone = false;
  1771.                     
  1772.                     while (!(lineDone || innerObjectDone)) 
  1773.                     {
  1774.                         tokenOp = ( *( (UInt32 *)dataPtr2 ) ) >> 24;
  1775.                         tokenData = ( *( (UInt32 *)dataPtr2 ) ) & 0x00ffffff;
  1776.                         
  1777.                         switch (tokenOp)
  1778.                         {
  1779.                             case kHitTestPixelsToken:
  1780.                                 // Now we can finally check for an intersection!!
  1781.                                     
  1782.                                 if (!(((xCount2 <= x1LeftDraw) && (xCount2+tokenData <= x1LeftDraw)) ||
  1783.                                       ((xCount2 >= x1RightDraw) && (xCount2+tokenData > x1RightDraw))))
  1784.                                 {
  1785.                                     intersect = true;
  1786.                                     goto done;
  1787.                                 }
  1788.                                     
  1789.                                 // if we are to the right of object1's drawing command, then we drop out of
  1790.                                 // the object2 loop.  Note that in this case we do not advance to the next
  1791.                                 // draw command in object2, as we might need to check the next drawing command
  1792.                                 // in object1 against it.
  1793.                                     
  1794.                                 if (xCount2+tokenData >= x1RightDraw)
  1795.                                 {
  1796.                                     innerObjectDone = true;
  1797.                                 }
  1798.                                 else
  1799.                                 {
  1800.                                     xCount2 += tokenData;
  1801.                                     dataPtr2 += sizeof( UInt32 );
  1802.                                 }
  1803.                                 break;
  1804.                                 
  1805.                             case kSkipPixelsToken:
  1806.                                 xCount2 += tokenData;
  1807.                                 dataPtr2 += sizeof( UInt32 );
  1808.                                 if (xCount2 > xIntersectRight)
  1809.                                     innerObjectDone = true;
  1810.                                 break;
  1811.                                 
  1812.                             case kLineStartToken:
  1813.                                 lineDone = true;
  1814.                                 break;
  1815.                             case kEndShapeToken:
  1816.                                 goto done;
  1817.                                 break;
  1818. #if qDebugging
  1819.                             default:
  1820.                                 Debugger();
  1821.                                 break;
  1822. #endif
  1823.                         } // end inner switch
  1824.                     } // end inner while loop
  1825.                     
  1826.                     // and make sure we exit if were at the end of the line in object1.
  1827.                     if (xCount1 >= xIntersectRight)
  1828.                         lineDone = true;
  1829.                     }
  1830.                     break;
  1831.                     
  1832.                 case kSkipPixelsToken:
  1833.                     xCount1 += tokenData;
  1834.                     if (xCount1 >= xIntersectRight)
  1835.                         lineDone = true;
  1836.                     break;
  1837.                 case kLineStartToken:
  1838.                     lineDone = true;
  1839.                     break;
  1840.                 case kEndShapeToken:
  1841.                     goto done;
  1842.                     break;
  1843. #if qDebugging
  1844.                 default:
  1845.                     Debugger();
  1846.                     break;
  1847. #endif
  1848.             }
  1849.         }            
  1850.         // skip to the next line for both and increment the count.
  1851.         dataPtr1 = nextDataPtr1;
  1852.         dataPtr2 = nextDataPtr2;
  1853.     } while (--yHeight > 0);
  1854.     
  1855.     
  1856.     done: 
  1857.     // If we got this far, we've dropped out of the bottom of the intersect area. 
  1858.     return intersect;
  1859. }
  1860.  
  1861.  
  1862.  
  1863. /*************************************************************************************
  1864. TGraphic::GraphicClipped
  1865. *************************************************************************************/
  1866.     
  1867. void
  1868. TGraphic::GraphicClipped (SInt32 top, SInt32 left, UInt32 clipLeft, UInt32 clipRight,
  1869.                           UInt32 clipTop, UInt32 clipBottom)
  1870.  
  1871. // This routine is almost identical to the one from Tips of the Mac Game Programming Gurus.
  1872. {
  1873.     UInt8    *rowStart;        // the pointer to the start of this row
  1874.     UInt8    *srcPtr;        // the current position in the sprite data
  1875.     UInt8    *destPtr;        // the current position in the destination pixmap
  1876.     UInt32    miscCounter;    // a counter for various purposes
  1877.     UInt32    extraCounter;    // a counter for right clippling purposes ( how much extra was there? )
  1878.     UInt32    tokenOp;        // the op code from the token
  1879.     UInt32    tokenData;        // the data from the token
  1880.     UInt32    yCount;            // how many lines do we have left to scan.
  1881.     UInt32    xCount;            // where are we in this line?
  1882.     
  1883.     // Determine the actual clipping area we're going to need to draw, we do these as UInt32s because
  1884.     // that's what we'll use when drawing.
  1885.         
  1886.     // set up the initial count of rows we'll want to search
  1887.     yCount = clipBottom-clipTop;
  1888.  
  1889.     // determine characteristics about the pixmap
  1890.     rowStart = gDestBaseAddr + (top + clipTop) * gRowBytes + left;
  1891.  
  1892.     // move to the start of the image data.  We'll do a quick skip of any initial pixel rows that we don't
  1893.     // need to worry about.
  1894.     srcPtr = (UInt8 *)( *fImage);
  1895.  
  1896.     // We do this to get rid of an optimizer error.  Normally, the destPtr and xCount get
  1897.     // set as part of the first token that gets interpreted by the loop.
  1898.     
  1899. #if qDebugging
  1900.     destPtr = (UInt8 *)0xDDDDDDDD;
  1901. #else
  1902.     destPtr = rowStart;
  1903. #endif    
  1904.     xCount = 0;  
  1905.  
  1906.     while (clipTop > 0)
  1907.     {
  1908.         clipTop--;
  1909.         tokenData = ( *( (UInt32 *)srcPtr ) ) & 0x00ffffff;
  1910.         srcPtr += sizeof( UInt32 ) + tokenData;
  1911.     }
  1912.     
  1913.     // start the loop
  1914.     do
  1915.     {
  1916.         // get a token
  1917.         tokenOp = ( *( (UInt32 *)srcPtr ) ) >> 24;
  1918.         tokenData = ( *( (UInt32 *)srcPtr ) ) & 0x00ffffff;
  1919.         srcPtr += sizeof( UInt32 );
  1920.             
  1921.         // depending on the token
  1922.         switch( tokenOp )
  1923.         {
  1924.             case kDrawPixelsToken:
  1925.                 miscCounter = tokenData;
  1926.                 extraCounter = 0;
  1927.                         
  1928.                 // if we need to, clip to the left
  1929.                 if( xCount < clipLeft )
  1930.                 {
  1931.                     // if this run does not appear at all, don't draw it
  1932.                     if ( miscCounter < clipLeft - xCount )
  1933.                     {
  1934.                         destPtr += miscCounter;
  1935.                         xCount += miscCounter;
  1936.                         miscCounter = ALIGN_TO_NEXT_LONG(miscCounter);                    
  1937.                         srcPtr += miscCounter;
  1938.  
  1939.                         break;
  1940.                     }
  1941.                     else
  1942.                     {
  1943.                         // if it does, skip to where we can draw
  1944.                         miscCounter -= clipLeft - xCount;
  1945.                         destPtr += clipLeft - xCount;
  1946.                         srcPtr += clipLeft - xCount;
  1947.                         xCount = clipLeft;
  1948.                     }
  1949.                 }
  1950.                         
  1951.                 // if we need to, clip to the right
  1952.                 if ( xCount + miscCounter > clipRight )
  1953.                 {
  1954.                     // if this run does not appear at all, skip it
  1955.                     if ( xCount > clipRight )
  1956.                     {
  1957.                         // once xCount is greater than xRight, no drawing commands will ever
  1958.                         // be issued on that line, so I changed the "gurus" code, which was actually
  1959.                         // wasting a couple of instructions setting variables that aren't needed.
  1960.                         //destPtr += miscCounter;
  1961.                         //xCount += miscCounter;
  1962.                         miscCounter = ALIGN_TO_NEXT_LONG(miscCounter);                    
  1963.                         srcPtr += miscCounter;
  1964.                         break;
  1965.                     }
  1966.                     else
  1967.                     {
  1968.                         // if it does, setup to draw what we can
  1969.                         extraCounter = (xCount + miscCounter) - clipRight;
  1970.                         miscCounter -= extraCounter;
  1971.                     }
  1972.                 }
  1973.                 
  1974.                 // adjust xCount for the run
  1975.                 xCount += miscCounter;
  1976.                         
  1977.                 // This blit loop is optimized to move 32 bytes or less.  On 604 machines, using an 8 byte move
  1978.                 // is faster in those rare cases where you can get them to align, and way slower when they don't.
  1979.                 // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
  1980.                 
  1981.                 
  1982.                 {
  1983.                 register UInt32 sixteenblits, blitloop;
  1984.                 sixteenblits = miscCounter >> 4;
  1985.                 for ( blitloop = 0; blitloop < sixteenblits; blitloop++)
  1986.                 {
  1987.                         register UInt32 temp1, temp2, temp3, temp4;
  1988.                         temp1 = ((UInt32 *) srcPtr)[0];
  1989.                         temp2 = ((UInt32 *) srcPtr)[1];
  1990.                         temp3 = ((UInt32 *) srcPtr)[2];
  1991.                         temp4 = ((UInt32 *) srcPtr)[3];
  1992.                         ((UInt32 *) destPtr)[0] = temp1;
  1993.                         ((UInt32 *) destPtr)[1] = temp2;
  1994.                         ((UInt32 *) destPtr)[2] = temp3;
  1995.                         ((UInt32 *) destPtr)[3] = temp4;
  1996.                         srcPtr += 16;
  1997.                         destPtr += 16;
  1998.                 }
  1999.                 // move any remaining data, up to 15 bytes total
  2000.                 if (miscCounter & 0x8)
  2001.                 {
  2002.                     register UInt32 temp1, temp2;
  2003.                     temp1 = ((UInt32 *) srcPtr)[0];
  2004.                     temp2 = ((UInt32 *) srcPtr)[1];
  2005.                     ((UInt32 *) destPtr)[0] = temp1;
  2006.                     ((UInt32 *) destPtr)[1] = temp2;
  2007.                     srcPtr += 8;
  2008.                     destPtr += 8;
  2009.                 }
  2010.                 if (miscCounter & 0x4)
  2011.                 {
  2012.                     register UInt32 temp1;
  2013.                     temp1 = *((UInt32 *) srcPtr);
  2014.                     srcPtr +=4;
  2015.                     *((UInt32 *) destPtr)  = temp1;
  2016.                     destPtr +=4;
  2017.                 }
  2018.                 if (miscCounter & 0x2)
  2019.                 {
  2020.                     register UInt16 temp1;
  2021.                     temp1 = *((UInt16 *) srcPtr);
  2022.                     srcPtr +=2;
  2023.                     *((UInt16 *) destPtr)  = temp1;
  2024.                     destPtr +=2;
  2025.                 }
  2026.                 if (miscCounter & 0x1)
  2027.                     *destPtr++ = *srcPtr++;
  2028.         
  2029.                 }
  2030.                         
  2031.                 // adjust for right clipping
  2032.                 destPtr += extraCounter;
  2033.                 srcPtr += extraCounter;
  2034.                 xCount += extraCounter;
  2035.                         
  2036.                 // adjust for the padding
  2037.                 srcPtr = (UInt8 *) ALIGN_TO_NEXT_LONG(srcPtr);    
  2038.                 break;
  2039.                         
  2040.             case kSkipPixelsToken:
  2041.                 destPtr += tokenData;
  2042.                 xCount += tokenData;
  2043.                 break;
  2044.                         
  2045.             case kLineStartToken:
  2046.                 // check to see if we're done drawing
  2047.                 if (yCount == 0)
  2048.                     return;
  2049.                 else
  2050.                 {
  2051.                     // set all the counters up
  2052.                     yCount--;
  2053.                     xCount = 0;
  2054.                     // set up the destination pointer
  2055.                     destPtr = rowStart;
  2056.                     rowStart += gRowBytes;
  2057.                 }
  2058.                 break;
  2059.                         
  2060.             case kEndShapeToken:
  2061.                 // exit.
  2062.                 return;
  2063.                 break;
  2064. #if qDebugging                        
  2065.             default:
  2066.                 // we should never get here
  2067.                 Debugger();
  2068.                 break;
  2069. #endif
  2070.         }
  2071.     } while (true);
  2072. }
  2073.  
  2074.  
  2075. /*************************************************************************************
  2076. TGraphic::GraphicUnclipped
  2077. *************************************************************************************/
  2078.  
  2079. void 
  2080. TGraphic::GraphicUnclipped (SInt32 top, SInt32 left)
  2081. {
  2082. // This routine is almost identical to the one from Tips of the Mac Game Programming Gurus.
  2083.  
  2084.     UInt8 *rowStart;        // the pointer to the start of this row
  2085.     UInt8 *srcPtr;            // the current position in the sprite data
  2086.     UInt8 *destPtr;            // the current position in the destination pixmap
  2087.     UInt32 miscCounter;        // a counter for various purposes
  2088.     UInt32 tokenOp;            // the op code from the token
  2089.     UInt32 tokenData;        // the data from the token
  2090.  
  2091.  
  2092. // If we are debugging and we have an invalid graphic, then destPtr might never be set
  2093. // up correctly.  This will force us to attempt to write to a bad location in memory.
  2094.     
  2095.     // determine characteristics about the pixmap
  2096.     rowStart = gDestBaseAddr + top * gRowBytes + left;
  2097.     
  2098.     // move to the start of the image data.
  2099.     srcPtr = (UInt8 *)( *fImage );
  2100.     
  2101. #if qDebugging
  2102.     destPtr = (UInt8 *) 0xDDDDDDDD;
  2103. #else
  2104.     destPtr = rowStart;
  2105. #endif    
  2106.     
  2107.     // Start looping
  2108.     do
  2109.     {
  2110.         // get a token
  2111.         tokenOp = ( *( (UInt32 *)srcPtr ) ) >> 24;
  2112.         tokenData = ( *( (UInt32 *)srcPtr ) ) & 0x00ffffff;
  2113.         srcPtr += sizeof( UInt32 );
  2114.             
  2115.         // depending on the token
  2116.         switch( tokenOp )
  2117.         {
  2118.             case kDrawPixelsToken:
  2119.                 miscCounter = tokenData;
  2120.                 
  2121.                 // This blit loop is optimized to move 32 bytes or less.  On 604 machines, using an 8 byte move
  2122.                 // is faster in those rare cases where you can get them to align, and way slower when they don't.
  2123.                 // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
  2124.                 
  2125.                 
  2126.                 {
  2127.                 register UInt32 sixteenblits, blitloop;
  2128.                 sixteenblits = miscCounter >> 4;
  2129.                 for ( blitloop = 0; blitloop < sixteenblits; blitloop++)
  2130.                 {
  2131.                         register UInt32 temp1, temp2, temp3, temp4;
  2132.                         temp1 = ((UInt32 *) srcPtr)[0];
  2133.                         temp2 = ((UInt32 *) srcPtr)[1];
  2134.                         temp3 = ((UInt32 *) srcPtr)[2];
  2135.                         temp4 = ((UInt32 *) srcPtr)[3];
  2136.                         ((UInt32 *) destPtr)[0] = temp1;
  2137.                         ((UInt32 *) destPtr)[1] = temp2;
  2138.                         ((UInt32 *) destPtr)[2] = temp3;
  2139.                         ((UInt32 *) destPtr)[3] = temp4;
  2140.                         srcPtr += 16;
  2141.                         destPtr += 16;
  2142.                 }
  2143.                 // move any remaining data, up to 15 bytes total
  2144.                 if (miscCounter & 0x8)
  2145.                 {
  2146.                     register UInt32 temp1, temp2;
  2147.                     temp1 = ((UInt32 *) srcPtr)[0];
  2148.                     temp2 = ((UInt32 *) srcPtr)[1];
  2149.                     ((UInt32 *) destPtr)[0] = temp1;
  2150.                     ((UInt32 *) destPtr)[1] = temp2;
  2151.                     srcPtr += 8;
  2152.                     destPtr += 8;
  2153.                 }
  2154.                 if (miscCounter & 0x4)
  2155.                 {
  2156.                     register UInt32 temp1;
  2157.                     temp1 = *((UInt32 *) srcPtr);
  2158.                     srcPtr +=4;
  2159.                     *((UInt32 *) destPtr)  = temp1;
  2160.                     destPtr +=4;
  2161.                 }
  2162.                 if (miscCounter & 0x2)
  2163.                 {
  2164.                     register UInt16 temp1;
  2165.                     temp1 = *((UInt16 *) srcPtr);
  2166.                     srcPtr +=2;
  2167.                     *((UInt16 *) destPtr)  = temp1;
  2168.                     destPtr +=2;
  2169.                 }
  2170.                 if (miscCounter & 0x1)
  2171.                     *destPtr++ = *srcPtr++;
  2172.         
  2173.                 }
  2174.                 
  2175.                 // adjust for the padding
  2176.                 srcPtr = (UInt8 *) ALIGN_TO_NEXT_LONG(srcPtr);    
  2177.                 break;
  2178.                         
  2179.             case kSkipPixelsToken:
  2180.                 destPtr += tokenData;
  2181.                 break;
  2182.                         
  2183.             case kLineStartToken:
  2184.                 // set up the destination pointer
  2185.                 destPtr = rowStart;
  2186.                 rowStart += gRowBytes;
  2187.                 break;
  2188.                         
  2189.             case kEndShapeToken:
  2190.                 // exit the routine
  2191.                 return;
  2192.                 break;
  2193. #if qDebugging
  2194.             default:
  2195.                 // we should never get here
  2196.                 Debugger();
  2197.                 break;
  2198. #endif
  2199.         }
  2200.     }    while( true );
  2201. }
  2202.  
  2203.  
  2204. /*************************************************************************************
  2205. TGraphic::BackgroundClipped
  2206.     
  2207. The Background routines work similarly to the standard graphic drawing routines,
  2208. but we keep an additional pointer to the destination graphics world, and we draw from
  2209. it, not the graphic data.  Later, we might optimize this routine further as we know
  2210. the two are always in sync.
  2211. *************************************************************************************/
  2212.  
  2213.  
  2214. void
  2215. TGraphic::BackgroundClipped (SInt32 top, SInt32 left, UInt32 clipLeft, UInt32 clipRight, 
  2216.                              UInt32 clipTop, UInt32 clipBottom)
  2217. {
  2218.     UInt8 *sourceRowStart;    // the pointer to the start of this row in the source
  2219.     UInt8 *destRowStart;    // the pointer to the start of this row in the dest
  2220.     UInt8 *srcPtr;            // the current position in the source pixmap
  2221.     UInt8 *destPtr;            // the current position in the destination pixmap
  2222.     UInt8 *dataPtr;            // the current position in the sprite data;
  2223.     UInt32 miscCounter;        // a counter for various purposes
  2224.     UInt32 extraCounter;    // a counter for right clippling purposes ( how much extra was there? )
  2225.     UInt32 tokenOp;            // the op code from the token
  2226.     UInt32 tokenData;        // the data from the token
  2227.     UInt32 yCount;            // how many lines do we still have to draw
  2228.     UInt32 xCount;            // where are we in this line?
  2229.  
  2230.     // determine characteristics about the pixmap
  2231.     sourceRowStart = gBackBaseAddr + (top + clipTop) * gRowBytes + left;
  2232.     destRowStart   = gDestBaseAddr + (top + clipTop) * gRowBytes + left;
  2233.     
  2234.     // move to the start of the image data.  We'll do a quick skip of any initial pixel
  2235.     // rows that we don't need to worry about.
  2236.     dataPtr = (UInt8 *)( *fImage);
  2237.     
  2238.     yCount = clipBottom - clipTop;
  2239.  
  2240. #if qDebugging
  2241.     srcPtr =  (UInt8 *) 0xDDDDDDDD;
  2242.     destPtr = (UInt8 *) 0xDDDDDDDD;
  2243. #else
  2244.     srcPtr = sourceRowStart;
  2245.     destPtr = destRowStart;
  2246. #endif    
  2247.     xCount = 0;
  2248.     
  2249.     while (clipTop > 0)
  2250.     {
  2251.         clipTop--;
  2252.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  2253.         dataPtr += sizeof( UInt32 ) + tokenData;
  2254.     }
  2255.     
  2256.     do
  2257.     {
  2258.         // get a token
  2259.         tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
  2260.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  2261.         dataPtr += sizeof( UInt32 );
  2262.             
  2263.         // depending on the token
  2264.         switch( tokenOp )
  2265.         {
  2266.             case kDrawPixelsToken:
  2267.                 miscCounter = tokenData;
  2268.                 extraCounter = 0;
  2269.                         
  2270.                 // advance the data pointer for free
  2271.                 tokenData = ALIGN_TO_NEXT_LONG (tokenData);
  2272.                 dataPtr += tokenData;
  2273.                         
  2274.                 // if we need to, clip to the left
  2275.                 if (xCount < clipLeft )
  2276.                 {
  2277.                     // if this run does not appear at all, don't draw it
  2278.                     if ( miscCounter < clipLeft - xCount )
  2279.                     {
  2280.                         destPtr += miscCounter;
  2281.                         srcPtr += miscCounter;
  2282.                         xCount += miscCounter;
  2283.                         break;
  2284.                     }
  2285.                     else
  2286.                     {
  2287.                     // if it does, skip to where we can draw
  2288.                         miscCounter -= clipLeft - xCount;
  2289.                         destPtr += clipLeft - xCount;
  2290.                         srcPtr += clipLeft - xCount;
  2291.                         xCount = clipLeft;
  2292.                     }
  2293.                 }
  2294.                         
  2295.                 // if we need to, clip to the right
  2296.                 if ( xCount + miscCounter > clipRight )
  2297.                 {
  2298.                     // if this run does not appear at all, skip it
  2299.                     if ( xCount > clipRight )
  2300.                         // once xCount is greater than xRight, no drawing commands will ever
  2301.                         // be issued on that line, so I changed the "gurus" code, which was actually
  2302.                         // wasting a couple of instructions setting variables that aren't needed.
  2303.                         //destPtr += miscCounter;
  2304.                         //srcPtr += miscCounter;
  2305.                         //xCount += miscCounter;
  2306.                         break;
  2307.                     else
  2308.                     {
  2309.                         // if it does, setup to draw what we can
  2310.                         extraCounter = (xCount + miscCounter) - clipRight;
  2311.                         miscCounter -= extraCounter;
  2312.                     }
  2313.                 }
  2314.                         
  2315.                 // adjust xCount for the run
  2316.                 xCount += miscCounter;
  2317.                 // This blit loop is optimized to move 32 bytes or less.  On 604 machines, using an 8 byte move
  2318.                 // is faster in those rare cases where you can get them to align, and way slower when they don't.
  2319.                 // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
  2320.                 
  2321.                 
  2322.                 {
  2323.                 register UInt32 sixteenblits, blitloop;
  2324.                 sixteenblits = miscCounter >> 4;
  2325.                 for ( blitloop = 0; blitloop < sixteenblits; blitloop++)
  2326.                 {
  2327.                         register UInt32 temp1, temp2, temp3, temp4;
  2328.                         temp1 = ((UInt32 *) srcPtr)[0];
  2329.                         temp2 = ((UInt32 *) srcPtr)[1];
  2330.                         temp3 = ((UInt32 *) srcPtr)[2];
  2331.                         temp4 = ((UInt32 *) srcPtr)[3];
  2332.                         ((UInt32 *) destPtr)[0] = temp1;
  2333.                         ((UInt32 *) destPtr)[1] = temp2;
  2334.                         ((UInt32 *) destPtr)[2] = temp3;
  2335.                         ((UInt32 *) destPtr)[3] = temp4;
  2336.                         srcPtr += 16;
  2337.                         destPtr += 16;
  2338.                 }
  2339.                 // move any remaining data, up to 15 bytes total
  2340.                 if (miscCounter & 0x8)
  2341.                 {
  2342.                     register UInt32 temp1, temp2;
  2343.                     temp1 = ((UInt32 *) srcPtr)[0];
  2344.                     temp2 = ((UInt32 *) srcPtr)[1];
  2345.                     ((UInt32 *) destPtr)[0] = temp1;
  2346.                     ((UInt32 *) destPtr)[1] = temp2;
  2347.                     srcPtr += 8;
  2348.                     destPtr += 8;
  2349.                 }
  2350.                 if (miscCounter & 0x4)
  2351.                 {
  2352.                     register UInt32 temp1;
  2353.                     temp1 = *((UInt32 *) srcPtr);
  2354.                     srcPtr +=4;
  2355.                     *((UInt32 *) destPtr)  = temp1;
  2356.                     destPtr +=4;
  2357.                 }
  2358.                 if (miscCounter & 0x2)
  2359.                 {
  2360.                     register UInt16 temp1;
  2361.                     temp1 = *((UInt16 *) srcPtr);
  2362.                     srcPtr +=2;
  2363.                     *((UInt16 *) destPtr)  = temp1;
  2364.                     destPtr +=2;
  2365.                 }
  2366.                 if (miscCounter & 0x1)
  2367.                     *destPtr++ = *srcPtr++;
  2368.         
  2369.                 }
  2370.                             
  2371.                 // adjust for right clipping
  2372.                 destPtr += extraCounter;
  2373.                 srcPtr += extraCounter;
  2374.                 xCount += extraCounter;
  2375.                         
  2376.                 break;
  2377.                         
  2378.             case kSkipPixelsToken:
  2379.                 destPtr += tokenData;
  2380.                 srcPtr += tokenData;
  2381.                         
  2382.                 xCount += tokenData;
  2383.                 break;
  2384.                         
  2385.             case kLineStartToken:
  2386.                 // check to see if we're done drawing
  2387.                 if (yCount == 0)
  2388.                     return;
  2389.                 else
  2390.                 {
  2391.                     // set all the counters up
  2392.                     yCount--;
  2393.                     xCount = 0;
  2394.                     // set up the source and destination pointers
  2395.                     destPtr = destRowStart;
  2396.                     srcPtr = sourceRowStart;
  2397.                     destRowStart += gRowBytes;
  2398.                     sourceRowStart += gRowBytes;
  2399.                 }
  2400.                 break;
  2401.             case kEndShapeToken:
  2402.                 return;
  2403.                 break;
  2404. #if qDebugging
  2405.             default:
  2406.             // we should never get here
  2407.             Debugger();
  2408.             break;
  2409. #endif
  2410.         }
  2411.     } while (true);
  2412. }
  2413.  
  2414. /*************************************************************************************
  2415. TGraphic::BackgroundUnclipped
  2416.     
  2417. The Background routines work similarly to the standard graphic drawing routines, but
  2418. we keep an additional pointer to the destination graphics world, and we draw from it,
  2419. not the graphic data.  Later, we might optimize this routine further as we know the
  2420. two are always in sync.
  2421. *************************************************************************************/
  2422.  
  2423. void 
  2424. TGraphic::BackgroundUnclipped (SInt32 top, SInt32 left)
  2425. {
  2426.     UInt8 *destRowStart;                // the pointer to the start of this row
  2427.     UInt8 *sourceRowStart;
  2428.     UInt8 *srcPtr;                        // the current position in the source pixmap
  2429.     UInt8 *destPtr;                        // the current position in the destination pixmap
  2430.     UInt8 *dataPtr;                        // the current position in the sprite data
  2431.     UInt32 miscCounter;                    // a counter for various purposes
  2432.     UInt32 tokenOp;                        // the op code from the token
  2433.     UInt32 tokenData;                    // the data from the token
  2434.     
  2435.     // determine characteristics about the pixmap
  2436.     destRowStart   = gDestBaseAddr + top * gRowBytes + left;
  2437.     sourceRowStart = gBackBaseAddr + top * gRowBytes + left;
  2438.     
  2439.     // move to the start of the graphic data
  2440.     dataPtr = (UInt8 *)( *fImage );
  2441.  
  2442. #if qDebugging
  2443.     srcPtr  = (UInt8 *) 0xDDDDDDDD;
  2444.     destPtr = (UInt8 *) 0xDDDDDDDD;
  2445. #else
  2446.     srcPtr = sourceRowStart;
  2447.     destPtr = destRowStart;
  2448. #endif    
  2449.     
  2450.     // loop until we are done
  2451.     do
  2452.     {
  2453.         // get a token
  2454.         tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
  2455.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  2456.         dataPtr += sizeof( UInt32 );
  2457.             
  2458.         // depending on the token
  2459.         switch( tokenOp )
  2460.         {
  2461.         case kDrawPixelsToken:
  2462.             miscCounter = tokenData;
  2463.             // adjust the data pointer
  2464.             tokenData = ALIGN_TO_NEXT_LONG (tokenData);
  2465.             dataPtr += tokenData;
  2466.     
  2467.                 // This blit loop is optimized to move 32 bytes or less.  On 604 machines, using an 8 byte move
  2468.                 // is faster in those rare cases where you can get them to align, and way slower when they don't.
  2469.                 // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
  2470.                 
  2471.                 
  2472.                 {
  2473.                 register UInt32 sixteenblits, blitloop;
  2474.                 sixteenblits = miscCounter >> 4;
  2475.                 for ( blitloop = 0; blitloop < sixteenblits; blitloop++)
  2476.                 {
  2477.                         register UInt32 temp1, temp2, temp3, temp4;
  2478.                         temp1 = ((UInt32 *) srcPtr)[0];
  2479.                         temp2 = ((UInt32 *) srcPtr)[1];
  2480.                         temp3 = ((UInt32 *) srcPtr)[2];
  2481.                         temp4 = ((UInt32 *) srcPtr)[3];
  2482.                         ((UInt32 *) destPtr)[0] = temp1;
  2483.                         ((UInt32 *) destPtr)[1] = temp2;
  2484.                         ((UInt32 *) destPtr)[2] = temp3;
  2485.                         ((UInt32 *) destPtr)[3] = temp4;
  2486.                         srcPtr += 16;
  2487.                         destPtr += 16;
  2488.                 }
  2489.                 // move any remaining data, up to 15 bytes total
  2490.                 if (miscCounter & 0x8)
  2491.                 {
  2492.                     register UInt32 temp1, temp2;
  2493.                     temp1 = ((UInt32 *) srcPtr)[0];
  2494.                     temp2 = ((UInt32 *) srcPtr)[1];
  2495.                     ((UInt32 *) destPtr)[0] = temp1;
  2496.                     ((UInt32 *) destPtr)[1] = temp2;
  2497.                     srcPtr += 8;
  2498.                     destPtr += 8;
  2499.                 }
  2500.                 if (miscCounter & 0x4)
  2501.                 {
  2502.                     register UInt32 temp1;
  2503.                     temp1 = *((UInt32 *) srcPtr);
  2504.                     srcPtr +=4;
  2505.                     *((UInt32 *) destPtr)  = temp1;
  2506.                     destPtr +=4;
  2507.                 }
  2508.                 if (miscCounter & 0x2)
  2509.                 {
  2510.                     register UInt16 temp1;
  2511.                     temp1 = *((UInt16 *) srcPtr);
  2512.                     srcPtr +=2;
  2513.                     *((UInt16 *) destPtr)  = temp1;
  2514.                     destPtr +=2;
  2515.                 }
  2516.                 if (miscCounter & 0x1)
  2517.                     *destPtr++ = *srcPtr++;
  2518.         
  2519.                 }
  2520.     
  2521.                 break;
  2522.                         
  2523.             case kSkipPixelsToken:
  2524.                 destPtr += tokenData;
  2525.                 srcPtr += tokenData;    
  2526.                 break;
  2527.                     
  2528.             case kLineStartToken:
  2529.                 // set up the source and destination
  2530.                 destPtr = destRowStart;
  2531.                 srcPtr = sourceRowStart;
  2532.                 destRowStart += gRowBytes;
  2533.                 sourceRowStart += gRowBytes;
  2534.                 break;
  2535.                         
  2536.             case kEndShapeToken:
  2537.                 // signal a loop exit
  2538.                 return;
  2539.                 break;
  2540. #ifdef qDebugging
  2541.             default:
  2542.                 // we should never get here
  2543.                 Debugger();
  2544.                 break;
  2545. #endif
  2546.         }
  2547.     } while (true);
  2548. }
  2549.  
  2550.  
  2551. /*************************************************************************************
  2552. TGraphic::DrawMaskUnclipped
  2553.     
  2554. This version of the drawing loop draws black anywhere the draw mask is active.
  2555. Useful for writing a PICT out to disk with the mask information.
  2556. *************************************************************************************/
  2557.  
  2558. void 
  2559. TGraphic::DrawMaskUnclipped (SInt32 top, SInt32 left)
  2560. {
  2561.     UInt8 *destRowStart;                // the pointer to the start of this row
  2562.     UInt8 *destPtr;                        // the current position in the destination pixmap
  2563.     UInt8 *dataPtr;                        // the current position in the sprite data
  2564.     UInt32 miscCounter;                    // a counter for various purposes
  2565.     UInt32 tokenOp;                        // the op code from the token
  2566.     UInt32 tokenData;                    // the data from the token
  2567.     UInt32 indexSmear;
  2568.     UInt32 indexSmear2;
  2569.     
  2570.     indexSmear = kMaskColorIndex;
  2571.     indexSmear |= (kMaskColorIndex << 8);
  2572.     indexSmear |= (indexSmear << 16);
  2573.     
  2574.     indexSmear2 = indexSmear;
  2575.     
  2576.     // determine characteristics about the pixmap
  2577.     destRowStart = gDestBaseAddr + top * gRowBytes + left;
  2578.     
  2579.     // move to the start of the graphic data
  2580.     dataPtr = (UInt8 *)( *fImage );
  2581.     
  2582. #if qDebugging
  2583.     destPtr = (UInt8 *) 0xDDDDDDDD;
  2584. #else
  2585.     destPtr = (UInt8 *) destRowStart;
  2586. #endif    
  2587.  
  2588.     // loop until we are done
  2589.     do
  2590.     {
  2591.         // get a token
  2592.         tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
  2593.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  2594.         dataPtr += sizeof( UInt32 );
  2595.             
  2596.         // depending on the token
  2597.         switch( tokenOp )
  2598.         {
  2599.         case kDrawPixelsToken:
  2600.             miscCounter = tokenData;
  2601.             // adjust the data pointer
  2602.             tokenData = ALIGN_TO_NEXT_LONG (tokenData);
  2603.             dataPtr += tokenData;
  2604.                 // This blit loop is optimized to move 32 bytes or less.  On 604 machines, using an 8 byte move
  2605.                 // is faster in those rare cases where you can get them to align, and way slower when they don't.
  2606.                 // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
  2607.                 
  2608.                 
  2609.                 {
  2610.                 register UInt32 sixteenblits, blitloop;
  2611.                 sixteenblits = miscCounter >> 4;
  2612.                 for (blitloop = 0; blitloop < sixteenblits; blitloop++)
  2613.                 {
  2614.                     ((UInt32 *) destPtr)[0] = *((UInt32 *) &indexSmear);
  2615.                     ((UInt32 *) destPtr)[1] = *((UInt32 *) &indexSmear);
  2616.                     ((UInt32 *) destPtr)[2] = *((UInt32 *) &indexSmear);
  2617.                     ((UInt32 *) destPtr)[3] = *((UInt32 *) &indexSmear);
  2618.                     destPtr += 16;
  2619.                 }
  2620.                 // move any remaining data, up to 15 bytes total
  2621.                 if (miscCounter & 0x8)
  2622.                 {
  2623.                     ((UInt32 *) destPtr)[0] = *((UInt32 *) &indexSmear);
  2624.                     ((UInt32 *) destPtr)[1] = *((UInt32 *) &indexSmear);
  2625.                     destPtr += 8;
  2626.                 }
  2627.                 if (miscCounter & 0x4)
  2628.                 {
  2629.                     *((UInt32 *) destPtr)  = *((UInt32 *) &indexSmear);
  2630.                     destPtr +=4;
  2631.                 }
  2632.                 if (miscCounter & 0x2)
  2633.                 {
  2634.                     *((UInt16 *) destPtr) = *((UInt16 *) &indexSmear);
  2635.                     destPtr +=2;
  2636.                 }
  2637.                 if (miscCounter & 0x1)
  2638.                     *destPtr++ = *((UInt8 *) &indexSmear);
  2639.         
  2640.                 }
  2641.     
  2642.                 break;
  2643.                         
  2644.             case kSkipPixelsToken:
  2645.                 destPtr += tokenData;
  2646.                 break;
  2647.                     
  2648.             case kLineStartToken:
  2649.                 // set up the source and destination
  2650.                 destPtr = destRowStart;
  2651.                 destRowStart += gRowBytes;
  2652.                 break;
  2653.                         
  2654.             case kEndShapeToken:
  2655.                 // signal a loop exit
  2656.                 return;
  2657.                 break;
  2658. #ifdef qDebugging
  2659.             default:
  2660.                 // we should never get here
  2661.                 Debugger();
  2662.                 break;
  2663. #endif
  2664.         }
  2665.     } while (true);
  2666. }
  2667.  
  2668. /*************************************************************************************
  2669. TGraphic::HitMaskUnclipped
  2670.     
  2671. Same as DrawMaskUnclipped, but using the fHitMask data instead.
  2672. *************************************************************************************/
  2673.  
  2674. void 
  2675. TGraphic::HitMaskUnclipped (SInt32 top, SInt32 left)
  2676. {
  2677.     UInt8 *destRowStart;                // the pointer to the start of this row
  2678.     UInt8 *destPtr;                        // the current position in the destination pixmap
  2679.     UInt8 *dataPtr;                        // the current position in the sprite data
  2680.     UInt32 miscCounter;                    // a counter for various purposes
  2681.     UInt32 tokenOp;                        // the op code from the token
  2682.     UInt32 tokenData;                    // the data from the token
  2683.     UInt32 indexSmear;
  2684.     UInt32 indexSmear2;
  2685.     
  2686.     indexSmear = kMaskColorIndex;
  2687.     indexSmear |= (kMaskColorIndex << 8);
  2688.     indexSmear |= (indexSmear << 16);
  2689.     
  2690.     indexSmear2 = indexSmear;
  2691.     
  2692.     // determine characteristics about the pixmap
  2693.     destRowStart = gDestBaseAddr + top * gRowBytes + left;
  2694.     
  2695.     // move to the start of the graphic data
  2696.     dataPtr = (UInt8 *)( *fHitMask );
  2697.  
  2698. #if qDebugging
  2699.     destPtr = (UInt8 *) 0xDDDDDDDD;
  2700. #else
  2701.     destPtr = destRowStart;
  2702. #endif    
  2703.     
  2704.     // loop until we are done
  2705.     do
  2706.     {
  2707.         // get a token
  2708.         tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
  2709.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  2710.         dataPtr += sizeof( UInt32 );
  2711.             
  2712.         // depending on the token
  2713.         switch( tokenOp )
  2714.         {
  2715.         case kDrawPixelsToken:
  2716.             miscCounter = tokenData;
  2717.     
  2718.                 // This blit loop is optimized to move 32 bytes or less.  On 604 machines, using an 8 byte move
  2719.                 // is faster in those rare cases where you can get them to align, and way slower when they don't.
  2720.                 // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
  2721.                 
  2722.                 
  2723.                 {
  2724.                 register UInt32 sixteenblits;
  2725.                 sixteenblits = miscCounter >> 4;
  2726.                 if (sixteenblits)
  2727.                 {
  2728.                     do
  2729.                     {
  2730.                         ((UInt32 *) destPtr)[0] = *((UInt32 *) &indexSmear);
  2731.                         ((UInt32 *) destPtr)[1] = *((UInt32 *) &indexSmear);
  2732.                         ((UInt32 *) destPtr)[2] = *((UInt32 *) &indexSmear);
  2733.                         ((UInt32 *) destPtr)[3] = *((UInt32 *) &indexSmear);
  2734.                         destPtr += 16;
  2735.                     }  while (--sixteenblits != 0);
  2736.                 }
  2737.                 // move any remaining data, up to 15 bytes total
  2738.                 if (miscCounter & 0x8)
  2739.                 {
  2740.                     ((UInt32 *) destPtr)[0] = *((UInt32 *) &indexSmear);
  2741.                     ((UInt32 *) destPtr)[1] = *((UInt32 *) &indexSmear);
  2742.                     destPtr += 8;
  2743.                 }
  2744.                 if (miscCounter & 0x4)
  2745.                 {
  2746.                     *((UInt32 *) destPtr)  = *((UInt32 *) &indexSmear);
  2747.                     destPtr +=4;
  2748.                 }
  2749.                 if (miscCounter & 0x2)
  2750.                 {
  2751.                     *((UInt16 *) destPtr) = *((UInt16 *) &indexSmear);
  2752.                     destPtr +=2;
  2753.                 }
  2754.                 if (miscCounter & 0x1)
  2755.                     *destPtr++ = *((UInt8 *) &indexSmear);
  2756.         
  2757.                 }
  2758.  
  2759.                 break;
  2760.                         
  2761.             case kSkipPixelsToken:
  2762.                 destPtr += tokenData;
  2763.                 break;
  2764.                     
  2765.             case kLineStartToken:
  2766.                 // set up the source and destination
  2767.                 destPtr = destRowStart;
  2768.                 destRowStart += gRowBytes;
  2769.                 break;
  2770.                         
  2771.             case kEndShapeToken:
  2772.                 // signal a loop exit
  2773.                 return;
  2774.                 break;
  2775. #ifdef qDebugging
  2776.             default:
  2777.                 // we should never get here
  2778.                 Debugger();
  2779.                 break;
  2780. #endif
  2781.         }
  2782.     } while (true);
  2783. }
  2784.  
  2785.